flutter學(xué)習(xí)筆記

flutter與RN的異同

  • 均實(shí)現(xiàn)了跨平臺(tái)
  • 都支持熱重載,開(kāi)發(fā)調(diào)試非常方便
  • RN基于React,使用js開(kāi)發(fā),受眾較廣,flutter則是使用Dart,受眾小,對(duì)于Java開(kāi)發(fā)人員來(lái)說(shuō)非常友好
  • 通俗來(lái)講,RN的UI框架是將JS轉(zhuǎn)化為原生控件,所以流暢度會(huì)比webview要高,而flutter則是從更底層進(jìn)行控件的繪制,直接廢棄了原生UI控件,性能要比RN更高!可以將flutter的應(yīng)用理解成一個(gè)跨平臺(tái)的游戲引擎寫(xiě)的游戲APP。
  • RN發(fā)展較早,比f(wàn)lutter穩(wěn)定,flutter的第三方庫(kù)還很少

flutter界面控件

在flutter中,所有控件都是widget,頁(yè)面(可以理解成Android的activity,iOS的controller)和應(yīng)用程序自身都是一個(gè)widget。

flutter中存在兩種widget,StatelessWidget用于定義無(wú)狀態(tài)控件,適用于顯示靜態(tài)文字、圖片等,這種控件在編譯運(yùn)行后無(wú)法更新內(nèi)容;StatefulWidget用于定義有狀態(tài)控件,后期可以通過(guò)調(diào)用setState方法來(lái)刷新內(nèi)容,用途更廣,更靈活。

flutter自帶了Material Design的整套UI設(shè)計(jì)控件,可構(gòu)建非常完整MD風(fēng)格的APP,也擁有用于當(dāng)前iOS設(shè)計(jì)語(yǔ)言的美麗和高保真widget。

詳細(xì)widget控件目錄可瀏覽flutter中文官網(wǎng)

flutter構(gòu)建頁(yè)面

在flutter中頁(yè)面自身也是widget,以下示例中的MaterialApp控件提供了MD風(fēng)格的整套UI模板,另外也有針對(duì)iOS風(fēng)格的CupertinoApp

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // 這個(gè)widget是這個(gè)應(yīng)用的根部widget
  @override
  Widget build(BuildContext context) { 
    return MyHomePage();
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);
  // 這是應(yīng)用的主頁(yè)widget,同時(shí)它是一個(gè)有狀態(tài)的widget,意味著它可以動(dòng)態(tài)刷新內(nèi)容
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() { 
      //當(dāng)你調(diào)用setState方法時(shí),會(huì)通知framework觸發(fā)build方法,刷新UI界面
      _counter++; 
    });
  }

  @override
  Widget build(BuildContext context) {
    //當(dāng)你條用setState方法,build方法就會(huì)被觸發(fā),刷新UI
    return  MaterialApp(
    //設(shè)置路由
     routes: < String, WidgetBuilder > {

      '/a':(_) => PageA(),
      '/b':(_) => PageB()},
      title: 'Flutter Demo',
      home: Scaffold(
        backgroundColor: Colors.white70,
        appBar: AppBar(
          title: Text('hello flutter'),
        ),
        body: Center( 
          child: Text('hello flutter onclick-count = $_counter'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

Screenshot_1550475894.png

值得注意的是MyApp自身是StatelessWidget,是無(wú)狀態(tài)的widget,但由于它內(nèi)部存在StatefulWidget,所以它是可以通過(guò)StatefulWidget來(lái)更改UI

flutter觸摸事件

flutter中,除了RaisedButton、FlatButton、IconButton等一系列按鈕控件外,其余widget是不具備onPressed屬性的,但是flutter提供了一個(gè)更加強(qiáng)大的手勢(shì)監(jiān)聽(tīng)widget:GestureDetector,支持單機(jī)、雙擊、長(zhǎng)按等常見(jiàn)觸摸事件,當(dāng)你某個(gè)widget需要某些觸摸事件時(shí),可在GestureDetector嵌套該widget。

GestureDetector(
            //雙擊
            onDoubleTap: (){

            },
            //長(zhǎng)按
            onLongPress: (){

            },
            //單擊
            onTap: (){

              _incrementCounter();
            },
            child: Text('hello flutter onclick-count = $_counter'),
          ), 

flutter頁(yè)面跳轉(zhuǎn)

路由分為靜態(tài)路由和動(dòng)態(tài)路由

靜態(tài)路由

有兩種注冊(cè)方式
1.修改主方法,用MaterialApp或其他WidgetsApp來(lái)包裹MyApp,設(shè)置路由

void main() => runApp(MaterialApp(home: MyApp(),
  routes: < String, WidgetBuilder > {

      '/a':(_) => PageA(),//頁(yè)面A
      '/b':(_) => PageB()//頁(yè)面B 
  },
)); 

2.直接在MyApp的類中設(shè)置屬性,請(qǐng)參考flutter構(gòu)建頁(yè)面這一章節(jié)

然后通過(guò)

//切換到B頁(yè)面
 Navigator.pushNamed(context, '/b');

動(dòng)態(tài)路由

動(dòng)態(tài)路由則不需要事先注冊(cè),靈活度更高,使用方式更多,方便傳值以及設(shè)置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

Navigator.push(context, PageRouteBuilder(pageBuilder: (BuildContext context, Animation < double > animation,
              Animation < double > secondaryAnimation) {
              //下一個(gè)頁(yè)面
              return Center(
                child: GestureDetector(
                  onTap: () {
                    //返回上一個(gè)頁(yè)面
                    Navigator.pop(context);
                  },
                  child: Text('haha'),
                ),
              );
            //構(gòu)建轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
            }, transitionsBuilder: (BuildContext context,
              Animation < double > animation,
              Animation < double > secondaryAnimation,
              Widget child) {
                //自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
              return new SlideTransition(
                position: new Tween < Offset > (
                  begin: const Offset(3.0, 0.0),
                    end: const Offset(0.0, 0.0),
                ).animate(animation),
                child: child,
              ).build(context);
            }));

如果你想使用系統(tǒng)默認(rèn)的動(dòng)畫(huà),推薦直接使用MaterialPageRoute

Navigator.push(context,MaterialPageRoute(builder: (context){
              //下一個(gè)頁(yè)面
              return Center(
                child: GestureDetector(

                  onTap: () {
                    //返回上一頁(yè)
                    Navigator.pop(context);
                    //返回上一頁(yè),并且返回一個(gè)200的值,可以是其他值,用于回調(diào)場(chǎng)景
                    //Navigator.pop(context,200);

                  },
                  child: Text('haha'),
                ),
              );
              //用于接收下一個(gè)頁(yè)面返回的值
            })).then((data){


              print(data);
            });

建議通過(guò)自定義StatefulWidget來(lái)構(gòu)建下一個(gè)可刷新的頁(yè)面,更便于傳值

Navigator.push(context,MaterialPageRoute(builder: (context){
              //Page為StatefulWidget參數(shù)即可達(dá)到傳值的效果
              return Page(id:'1023');
            }));

flutter與原生交互

Android

首先,在flutter中聲名如下方法

 Future<Null> _tryConnectAndroid() async {
      
          try { 
              //注冊(cè)方法頻道
              MethodChannel platform = MethodChannel('samples.test/test');
              //第一個(gè)參數(shù) tryToast為Java/oc中的方法名(后面會(huì)講),第二個(gè)參數(shù)數(shù)組為傳參數(shù)組
              String result= await platform.invokeMethod('tryToast',[{'msg':"flutter connect android"}]);}
              //result 為回調(diào)的結(jié)果
              on PlatformException catch (e){ 
                  
              }
 
    }

然后在flutter項(xiàng)目的Android目錄找到MainActivity

public class MainActivity extends FlutterActivity {
  //需要與flutter的MethodChannel名稱對(duì)應(yīng)
  static String CHANNEL="samples.test/test";
  private int count = 0;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
     //注冊(cè)方法
    new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
      new MethodCallHandler() {
          @Override
          public void onMethodCall(MethodCall call, Result result) {
              //找到對(duì)應(yīng)的方法名
              if (call.method.equals("tryToast")) {
                  //傳遞過(guò)來(lái)的參數(shù)列表
                  ArrayList arguments = (ArrayList)call.arguments;
                  String msg =((Map<String,String>)arguments.get(0)).get("msg");
                  //回調(diào)結(jié)果
                  result.success("hello flutter");
                // start();
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_LONG).show();

              }

          }
      });
  }


  
}

iOS

iOS的請(qǐng)參考此鏈接

flutter打包apk與ipa

apk打包

apk打包相對(duì)簡(jiǎn)單,和以往的Android打包一樣,在gradle文件里配置好簽名信息等,運(yùn)行一下指令即可

flutter build apk

IPA的請(qǐng)參考此鏈接

總結(jié)

學(xué)習(xí)flutter兩三個(gè)星期,一開(kāi)始被它多重嵌套的UI寫(xiě)法嚇到了,后來(lái)習(xí)慣下來(lái)還是比較得心應(yīng)手的,雖然寫(xiě)UI的時(shí)候不能像Android寫(xiě)xml一樣能夠即使預(yù)覽,但是得益于熱重載的功能,實(shí)際上你一邊寫(xiě)UI一邊在模擬器和手機(jī)上預(yù)覽UI也是完全沒(méi)有問(wèn)題的。flutter提供了大量的UI控件,方便開(kāi)發(fā)者靈活使用,像上文所說(shuō),flutter是直接拋棄了原生控件,通過(guò)圖像引擎利用Android/iOS的畫(huà)布將UI繪制出來(lái),性能當(dāng)然要比RN通過(guò)JavaScript轉(zhuǎn)換成原生UI控件要高,通過(guò)Android手機(jī)查看基于flutter縮寫(xiě)APP的UI層級(jí)時(shí),會(huì)發(fā)現(xiàn)APP的UI只有一個(gè)層級(jí),它是一個(gè)整體的View,不像以往Android需要進(jìn)一步優(yōu)化布局層級(jí)。

flutter的定義是極速構(gòu)建漂亮的原生應(yīng)用,是一套移動(dòng)UI框架,flutter只是能夠幫助開(kāi)發(fā)者更有效率地構(gòu)建UI,如果APP的業(yè)務(wù)需要調(diào)用大量的手機(jī)系統(tǒng)特性時(shí),開(kāi)發(fā)者仍需要轉(zhuǎn)移到原生開(kāi)發(fā)中,所以開(kāi)發(fā)者能夠同時(shí)掌握Android、iOS開(kāi)發(fā)就最好不過(guò)了。

更多關(guān)于flutter的文檔可查閱此鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容