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),
),
),
);
}
}

值得注意的是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的文檔可查閱此鏈接