Google 出品扮休,Dart語言掸哑,F(xiàn)lutter Engine引擎鼻由,響應(yīng)式設(shè)計模式,原生渲染橱赠。
目錄
1. 什么是Flutter
- 現(xiàn)有移動平臺:
蘋果的iOS SDKs發(fā)布于2008年尤仍,谷歌的Android軟件開發(fā)工具包發(fā)布于2009年,這兩種sdk包是基于不同的編程語言的狭姨,分別是Objective-C和Java, 如下是大概的結(jié)構(gòu)圖:
-
Flutter:
是谷歌2018年發(fā)布的跨平臺移動UI框架宰啦,與 react native 和 weex 的通過 Javascript 開發(fā)不同,F(xiàn)lutter 的編程語言是Drat饼拍,(谷歌親兒子赡模,據(jù)說是因為 Drat 項目組就在 Flutter 隔壁而被選上(???))所以執(zhí)行時并不需要 Javascript 引擎。
Flutter提供響應(yīng)式的視圖师抄,提供Dart語言編譯多個平臺的原生代碼漓柑,因此可以直接和平臺通信,同時使用Skia圖形引擎來完成圖形叨吮、文本辆布、圖像、動畫等繪制茶鉴,擁有自己獨立的一套圖形系統(tǒng)锋玲,不再依賴于原生。避免由JavaScript橋接器引起的性能問題涵叮。
Skia:這個是谷歌的一個跨平臺渲染框架惭蹂,從目前iOS和Anrdroid來看伞插,Skia底層最終都是調(diào)用OpenGL繪制。
得益于 Engine 層盾碗,F(xiàn)lutter 甚至不使用移動平臺的原生控件媚污, 而是使用自己 Engine 來繪制 Widget (Flutter的顯示單元),而 Dart 代碼都是通過 AOT 編譯為平臺的原生代碼廷雅,所以 Flutter 可以直接與平臺通信耗美,不需要JS引擎的橋接。同時 Flutter 唯一要求系統(tǒng)提供的是 canvas榜轿,以實現(xiàn)UI的繪制幽歼。
Dart 還可以編譯成 ARM 和 x86 代碼直接運行在 iOS、Android 設(shè)備上谬盐。Dart 同時支持 JIT 和 AOT甸私。 Just-in-time Compiler(運行時編譯 動態(tài)編譯) Ahead-of-time Compiler(運行前編譯 靜態(tài)編譯)
2. Flutter框架架構(gòu)
如上圖,F(xiàn)lutter 主要分為 Framework 和 Engine飞傀,我們基于Framework 開發(fā)App皇型,運行在 Engine 上。Engine 是 Flutter 的獨立虛擬機砸烦,由它適配和提供跨平臺支持弃鸦。
3. 使用Flutter進行開發(fā)
在Flutter中,幾乎所有東西都是一個widget - 甚至布局模型都是widget幢痘。您在Flutter應(yīng)用中看到的圖像唬格、圖標和文本都是widget。 甚至你看不到的東西也是widget颜说,例如行(row)购岗、列(column)以及用來排列、約束和對齊這些可見widget的網(wǎng)格门粪。
- Widgets
-
Widget生命周期
Flutter提供兩種類型的Widget, StatelessWidget 和 StatefulWidget喊积,前者為狀態(tài)不可變,后者可以通過setState()改變state來改變更新UI玄妈,開發(fā)者可以根據(jù)自己的實際情況使用
StatefulWidget:
7.jpgStatelessWidget:
8.jpeg -
iOS風(fēng)格Widget
Cupertino (iOS風(fēng)格) 類型 作用特點 CupertinoNavigationBar An iOS-style top navigation bar CupertinoTabBar An iOS-style bottom tab bar CupertinoActivityIndicator 一個iOS風(fēng)格的loading指示器乾吻。顯示一個圓形的轉(zhuǎn)圈菊花 CupertinoAlertDialog 一iOS風(fēng)格的alert dialog. CupertinoButton iOS風(fēng)格的button. CupertinoDialog iOS風(fēng)格的對話框,沒有按鈕 CupertinoSlider An iOS-style slider CupertinoSwitch An iOS-style switch. CupertinoPicker An iOS-style picker control. CupertinoPageTransition Provides an iOS-style page transition animation. CupertinoFullscreenDialogTransition An iOS-style transition used for summoning fullscreen dialogs. -
Material風(fēng)格Widget
Material類型 作用特點 Scaffold Material Design布局結(jié)構(gòu)的基本實現(xiàn)。此類提供了用于顯示drawer拟蜻、snackbar和底部sheet的API绎签。 Appbar 一個Material Design應(yīng)用程序欄,由工具欄和其他可能的widget(如TabBar和FlexibleSpaceBar)組成酝锅。 BottomNavigationBar 底部導(dǎo)航條辜御,可以很容易地在tap之間切換和瀏覽頂級視圖。 TabBar 一個顯示水平選項卡的Material Design widget屈张。 TabBarView 顯示與當前選中的選項卡相對應(yīng)的頁面視圖擒权。通常和TabBar一起使用。 MaterialApp 一個方便的widget阁谆,它封裝了應(yīng)用程序?qū)崿F(xiàn)Material Design所需要的一些widget碳抄。 WidgetsApp 一個方便的類,它封裝了應(yīng)用程序通常需要的一些widget场绿。 Drawer 從Scaffold邊緣水平滑動以顯示應(yīng)用程序中導(dǎo)航鏈接的Material Design面板剖效。 Image Image.asset Image.network Image.file Image.memory Icon A Material Design icon. RaisedButton Material Design中的button, 一個凸起的材質(zhì)矩形按鈕 RaisedButton Material Design中的button焰盗, 一個凸起的材質(zhì)矩形按鈕 FloatingActionButton 一個圓形圖標按鈕璧尸,它懸停在內(nèi)容之上,以展示應(yīng)用程序中的主要動作熬拒。FloatingActionButton通常用于Scaffold.floatingActionButton字段爷光。 FlatButton 一個扁平的Material按鈕 IconButton 一個Material圖標按鈕,點擊時會有水波動畫 PopupMenuButton 當菜單隱藏式澎粟,點擊或調(diào)用onSelected時顯示一個彈出式菜單列表 ButtonBar 水平排列的按鈕組 TextField 文本輸入框 Checkbox 復(fù)選框蛀序,允許用戶從一組中選擇多個選項。 Radio 單選框活烙,允許用戶從一組中選擇一個選項徐裸。 Switch On/off 用于切換一個單一狀態(tài) Slider 滑塊,允許用戶通過滑動滑塊來從一系列值中選擇啸盏。 Date & Time Pickers 日期&時間選擇器 SimpleDialog 簡單對話框可以顯示附加的提示或操作 AlertDialog 一個會中斷用戶操作的對話款重贺,需要用戶確認 BottomSheet BottomSheet是一個從屏幕底部滑起的列表(以顯示更多的內(nèi)容)。你可以調(diào)用showBottomSheet()或showModalBottomSheet彈出 SnackBar 具有可選操作的輕量級消息提示回懦,在屏幕的底部顯示气笙。 Card 一個 Material Design 卡片。擁有一個圓角和陰影 ListTile 一個固定高度的行粉怕,通常包含一些文本健民,以及一個行前或行尾圖標。 Divider 一個邏輯1像素厚的水平分割線贫贝,兩邊都有填充 Placeholder 一個繪制了一個盒子的的widget秉犹,代表日后有widget將會被添加到該盒子中 RefreshIndicator 內(nèi)置下拉刷新控件 ListView 可以有多個子 Widget。
-
負責Layout的Widget
Flutter 中擁有需要將近30種內(nèi)置的 布局Widget稚晚,其中常用有 Container崇堵、Padding、Center客燕、Flex鸳劳、Stack、Row也搓、Colum等赏廓,下面簡單講解它們的特性和使用涵紊。
類型 | 作用特點 |
---|---|
Container | 只有一個子 Widget。默認充滿幔摸,包含了padding摸柄、margin、constraints既忆、color驱负、width、height患雇、decoration跃脊、alignment、transform苛吱。 |
Padding | 只有一個子 Widget酪术。只用于設(shè)置Padding,常用于嵌套child又谋,給child設(shè)置padding拼缝。 |
Center | 只有一個子 Widget。只用于居中顯示彰亥,常用于嵌套child咧七,給child設(shè)置居中。 |
Stack | 可以有多個子 Widget任斋。 子Widget堆疊在一起继阻。 |
Colum | 可以有多個子 Widget。垂直布局废酷。 |
Row | 可以有多個子 Widget瘟檩。水平布局。 |
Expanded | 只有一個子 Widget澈蟆。在 Colum 和 Row 中充滿墨辛。 |
- 布局方式
在iOS系統(tǒng)中,我們使用frame來進行UI布局趴俘,同時可以通過addChild和removeChild添加或者移除視圖睹簇。
但是在Flutter中,Widget 是不可變的寥闪,可以傳入一個函數(shù)太惠,該函數(shù)返回一個子Widget 給父 Widget。并在該函數(shù)中通過一個 bool 值來控制子 Widget 的創(chuàng)建疲憋。
children: <Widget>[
new Padding(
padding:
const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: new RaisedButton(
textColor: Colors.black,
child: new Text('opacity'),
onPressed: () {
setState(() {
_aniIndex = 0;
});
}),
),
],
- 事件監(jiān)聽
Flutter中有兩種方式來處理touch:
一是直接傳遞一個處理事件的方法給Widget凿渊;
或者通過GestureDetector來實現(xiàn)事件監(jiān)聽與處理。
new Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: new GestureDetector(
onTapDown: (tapDown) {
setState(() {
tapEvent = '這是GestureDetector監(jiān)聽的onTapDown事件';
});
},
onTapUp: (tapUp) {
setState(() {
tapEvent = '這是GestureDetector監(jiān)聽的onTapUp事件';
});
},
onTapCancel: () {
setState(() {
tapEvent = '這是GestureDetector監(jiān)聽的onTapCancel事件';
});
},
onDoubleTap: () {
setState(() {
tapEvent = '這是GestureDetector監(jiān)聽的onDoubleTap事件';
});
},
onLongPress: () {
setState(() {
tapEvent = '這是GestureDetector監(jiān)聽的onLongPress事件';
});
},
child: new BorderButton('GestureDetector onTap 分解事件按鈕'),
),
),
- 動畫
// 創(chuàng)建 AnimationController 對象
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 2000));
//非線性動畫
final CurvedAnimation curvedAnimation = CurvedAnimation(
parent: controller,curve: Curves.elasticInOut);
// 通過 Tween 對象 創(chuàng)建 Animation 對象
animation = Tween(begin: 50.0, end: 200.0).animate(curvedAnimation)
//Calls the listener every time the value of the animation changes.
..addListener(() {
// 注意:這句不能少,否則 widget 不會重繪埃脏,也就看不到動畫效果
setState(() {});
})
// Calls listener every time the status of the animation changes.
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
controller.forward();
}
});
// 執(zhí)行動畫
controller.forward();
// 做動畫的widget
body: Center(
child: Container(
width: animation.value,
height: animation.value,
decoration: BoxDecoration(
color: Colors.redAccent
),
),
),
-
數(shù)據(jù)交互
Flutter 是支持原生頁面和 Flutter 頁面混合開發(fā)的搪锣,但是不支持原生組件在Flutter 中使用,原生端有 MethodChannel 來支持 Flutter 對原生的一些API調(diào)用剂癌。
flutter --> 原生
// flutter
Future<Null> _launchPlatformCount() async {
final int platformCounter =
await _methodChannel.invokeMethod('switchView', _counter);
setState(() {
_counter = platformCounter;
});
}
// iOS
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"samples.flutter.io/platform_view" binaryMessenger:controller];
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"switchView" isEqualToString:call.method]) {
_flutterResult = result;
PlatformViewController* platformViewController =
[controller.storyboard instantiateViewControllerWithIdentifier:@"PlatformView"];
platformViewController.counter = ((NSNumber*)call.arguments).intValue;
platformViewController.delegate = self;
UINavigationController* navigationController =
[[UINavigationController alloc] initWithRootViewController:platformViewController];
navigationController.navigationBar.topItem.title = @"Platform View";
[controller presentViewController:navigationController animated:NO completion:nil];
} else {
result(FlutterMethodNotImplemented);
}
}];
// FlutterResult是一個回調(diào)函數(shù)
- 網(wǎng)絡(luò)請求
// 把方法聲明為異步方法,通過await關(guān)鍵字等待該異步方法執(zhí)行完成
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
// http.Response response = await http.get(dataURL);
// setState(() {
// widgets = json.decode(response.body);
// });
Dio dio = new Dio();
Response response = await dio.get(dataURL);
setState(() {
widgets = response.data;
});
}
-
路由導(dǎo)航
Flutter 中的頁面跳轉(zhuǎn)是通過 Navigator 實現(xiàn)的淤翔,路由跳轉(zhuǎn)又分為:帶參數(shù)跳轉(zhuǎn)和不帶參數(shù)跳轉(zhuǎn)。不帶參數(shù)跳轉(zhuǎn)比較簡單佩谷,默認可以通過 MaterialApp 的路由表跳轉(zhuǎn);而帶參數(shù)的跳轉(zhuǎn)监嗜,參數(shù)通過跳轉(zhuǎn)頁面的構(gòu)造方法傳遞谐檀。常用的跳轉(zhuǎn)有如下幾種使用:
///不帶參數(shù)的路由表跳轉(zhuǎn)
Navigator.pushNamed(context, routeName);
///跳轉(zhuǎn)新頁面并且替換,比如登錄頁跳轉(zhuǎn)主頁
Navigator.pushReplacementNamed(context, routeName);
///跳轉(zhuǎn)到新的路由裁奇,并且關(guān)閉給定路由的之前的所有頁面
Navigator.pushNamedAndRemoveUntil(context, '/calendar', ModalRoute.withName('/'));
///帶參數(shù)的路由跳轉(zhuǎn)桐猬,并且監(jiān)聽返回
Navigator.push(context, new MaterialPageRoute(builder: (context) => new NotifyPage())).then((res) {
///獲取返回處理
});
可以看到,Navigator 的 push 返回的是一個 Future刽肠,這個Future 的作用是在頁面返回時被調(diào)用的溃肪。也就是你可以通過 Navigator 的 pop 時返回參數(shù),之后在 Future 中可以的監(jiān)聽中處理頁面的返回結(jié)果音五。
@optionalTypeArgs
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
return Navigator.of(context).push(route);
}
4. Flutter和原生PK
- 內(nèi)存對比
-
啟動速度
10.jpg
-
包大小對比
11.jpg
-
兼容性對比
Flutter 所提供的所有的 Widget 動畫還有事件機制都是基于skia來實現(xiàn)的惫撰,與平臺無關(guān),所以有很高的跨平臺的兼容性躺涝。但是獨立的 UI 系統(tǒng)導(dǎo)致了厨钻,很多Android/iOS 對應(yīng)的工具無法使用。
移動操作系統(tǒng):Android Jelly Bean坚嗜,v16,4.1.x或更新的版本以及iOS 8或更新版本夯膀。
移動硬件:64位iOS設(shè)備(從iPhone 5S和更新的iPhone型號開始)以及ARM Android設(shè)備。
請注意苍蔬,我們目前不支持:
● ARM32 iOS設(shè)備(iPhone 4诱建,iPhone 5)
● x86 Android設(shè)備(好像不多吧)
5. 總結(jié)
-
Flutter 的優(yōu)點:
● 熱重載(Hot Reload),利用提供的IDE直接保存代碼并重載碟绑,手機或者模擬器立馬就可以看見效果俺猿,這一點調(diào)試起來很方便。
● Widget的理念蜈敢,對于Flutter來說辜荠,手機應(yīng)用里的所有組件都是Widget,通過可組合的空間集合抓狭、豐富的動畫庫以及分層可擴展的架構(gòu)實現(xiàn)了富有感染力的靈活界面設(shè)計伯病。
● 借助GPU加速的渲染引擎以及高性能本地代碼運行時以達到跨平臺設(shè)備的高質(zhì)量用戶體驗。
-
Flutter 的不足:
● 開發(fā)語言是基于Dart, 對開發(fā)者而言,增加了不少學(xué)習(xí)成本午笛。
● UI布局方面惭蟋,層次不夠明顯,不那么直接药磺,復(fù)雜化了程序的可讀性告组。
● Flutter是一種新的框架,目前市面上應(yīng)用和社區(qū)不太成熟癌佩,而且支持的庫不如ReactNative及原生木缝。
● 目前Dart代碼會AOT編譯到native,不像ReactNative围辙,支持熱更新起來會很難我碟,但從API的結(jié)構(gòu)設(shè)計上來看,后期應(yīng)該很快會實現(xiàn)熱更新姚建。
● 不能支持原生組件在Flutter中顯示矫俺,導(dǎo)致很多組件需要重新開發(fā),不如ReactNative靈活掸冤。
● 現(xiàn)在還不支持HTML
● bate版 0.58
總之從Flutter的設(shè)計理念來看厘托,整體架構(gòu)都是具有革命性的,相比于其他跨平臺實現(xiàn)了真正意義的跨平臺稿湿,各平臺體驗一致铅匹,而且讓用戶體驗達到了最優(yōu),各種UI庫和組件也在不斷的增加缎罢,各種生態(tài)系統(tǒng)和社區(qū)在不斷的完善伊群,對于以后新的操作系統(tǒng)適配性會更強,如Fuchsia系統(tǒng)策精,非常值得大家了解和學(xué)習(xí)舰始,相信不久的將來,會慢慢成熟起來咽袜,成為主流開發(fā)語言丸卷。