為您解碼網(wǎng)站建設(shè)的點(diǎn)點(diǎn)滴滴
發(fā)表日期:2018-09 文章編輯:小燈 瀏覽次數(shù):1976
Google 出品,Dart語言,F(xiàn)lutter Engine引擎,響應(yīng)式設(shè)計(jì)模式,原生渲染。
目錄
蘋果的iOS SDKs發(fā)布于2008年,谷歌的Android軟件開發(fā)工具包發(fā)布于2009年,這兩種sdk包是基于不同的編程語言的,分別是Objective-C和Java, 如下是大概的結(jié)構(gòu)圖:
Flutter提供響應(yīng)式的視圖,提供Dart語言編譯多個(gè)平臺(tái)的原生代碼,因此可以直接和平臺(tái)通信,同時(shí)使用Skia圖形引擎來完成圖形、文本、圖像、動(dòng)畫等繪制,擁有自己獨(dú)立的一套圖形系統(tǒng),不再依賴于原生。避免由JavaScript橋接器引起的性能問題。
Skia:這個(gè)是谷歌的一個(gè)跨平臺(tái)渲染框架,從目前iOS和Anrdroid來看,Skia底層最終都是調(diào)用OpenGL繪制。
得益于 Engine 層,F(xiàn)lutter 甚至不使用移動(dòng)平臺(tái)的原生控件, 而是使用自己Engine 來繪制 Widget (Flutter的顯示單元),而 Dart 代碼都是通過 AOT 編譯為平臺(tái)的原生代碼,所以 Flutter 可以直接與平臺(tái)通信,不需要JS引擎的橋接。同時(shí) Flutter 唯一要求系統(tǒng)提供的是 canvas,以實(shí)現(xiàn)UI的繪制。
Dart 還可以編譯成 ARM 和 x86 代碼直接運(yùn)行在 iOS、Android 設(shè)備上。Dart 同時(shí)支持 JIT 和 AOT。Just-in-time Compiler(運(yùn)行時(shí)編譯 動(dòng)態(tài)編譯)Ahead-of-time Compiler(運(yùn)行前編譯 靜態(tài)編譯)
如上圖,F(xiàn)lutter 主要分為 Framework 和 Engine,我們基于Framework 開發(fā)App,運(yùn)行在 Engine 上。Engine 是 Flutter 的獨(dú)立虛擬機(jī),由它適配和提供跨平臺(tái)支持。
在Flutter中,幾乎所有東西都是一個(gè)widget - 甚至布局模型都是widget。您在Flutter應(yīng)用中看到的圖像、圖標(biāo)和文本都是widget。 甚至你看不到的東西也是widget,例如行(row)、列(column)以及用來排列、約束和對(duì)齊這些可見widget的網(wǎng)格。
Widget生命周期
Flutter提供兩種類型的Widget, StatelessWidget 和 StatefulWidget,前者為狀態(tài)不可變,后者可以通過setState()改變state來改變更新UI,開發(fā)者可以根據(jù)自己的實(shí)際情況使用
StatefulWidget:
StatelessWidget:
iOS風(fēng)格Widget
Cupertino (iOS風(fēng)格) 類型 | 作用特點(diǎn) |
---|---|
CupertinoNavigationBar | An iOS-style top navigation bar |
CupertinoTabBar | An iOS-style bottom tab bar |
CupertinoActivityIndicator | 一個(gè)iOS風(fēng)格的loading指示器。顯示一個(gè)圓形的轉(zhuǎn)圈菊花 |
CupertinoAlertDialog | 一iOS風(fēng)格的alert dialog. |
CupertinoButton | iOS風(fēng)格的button. |
CupertinoDialog | iOS風(fēng)格的對(duì)話框,沒有按鈕 |
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類型 | 作用特點(diǎn) |
---|---|
Scaffold | Material Design布局結(jié)構(gòu)的基本實(shí)現(xiàn)。此類提供了用于顯示drawer、snackbar和底部sheet的API。 |
Appbar | 一個(gè)Material Design應(yīng)用程序欄,由工具欄和其他可能的widget(如TabBar和FlexibleSpaceBar)組成。 |
BottomNavigationBar | 底部導(dǎo)航條,可以很容易地在tap之間切換和瀏覽頂級(jí)視圖。 |
TabBar | 一個(gè)顯示水平選項(xiàng)卡的Material Design widget。 |
TabBarView | 顯示與當(dāng)前選中的選項(xiàng)卡相對(duì)應(yīng)的頁(yè)面視圖。通常和TabBar一起使用。 |
MaterialApp | 一個(gè)方便的widget,它封裝了應(yīng)用程序?qū)崿F(xiàn)Material Design所需要的一些widget。 |
WidgetsApp | 一個(gè)方便的類,它封裝了應(yīng)用程序通常需要的一些widget。 |
Drawer | 從Scaffold邊緣水平滑動(dòng)以顯示應(yīng)用程序中導(dǎo)航鏈接的Material Design面板。 |
Image | Image.assetImage.networkImage.fileImage.memory |
Icon | A Material Design icon. |
RaisedButton | Material Design中的button, 一個(gè)凸起的材質(zhì)矩形按鈕 |
RaisedButton | Material Design中的button, 一個(gè)凸起的材質(zhì)矩形按鈕 |
FloatingActionButton | 一個(gè)圓形圖標(biāo)按鈕,它懸停在內(nèi)容之上,以展示應(yīng)用程序中的主要?jiǎng)幼?。FloatingActionButton通常用于Scaffold.floatingActionButton字段。 |
FlatButton | 一個(gè)扁平的Material按鈕 |
IconButton | 一個(gè)Material圖標(biāo)按鈕,點(diǎn)擊時(shí)會(huì)有水波動(dòng)畫 |
PopupMenuButton | 當(dāng)菜單隱藏式,點(diǎn)擊或調(diào)用onSelected時(shí)顯示一個(gè)彈出式菜單列表 |
ButtonBar | 水平排列的按鈕組 |
TextField | 文本輸入框 |
Checkbox | 復(fù)選框,允許用戶從一組中選擇多個(gè)選項(xiàng)。 |
Radio | 單選框,允許用戶從一組中選擇一個(gè)選項(xiàng)。 |
Switch | On/off 用于切換一個(gè)單一狀態(tài) |
Slider | 滑塊,允許用戶通過滑動(dòng)滑塊來從一系列值中選擇。 |
Date & Time Pickers | 日期&時(shí)間選擇器 |
SimpleDialog | 簡(jiǎn)單對(duì)話框可以顯示附加的提示或操作 |
AlertDialog | 一個(gè)會(huì)中斷用戶操作的對(duì)話款,需要用戶確認(rèn) |
BottomSheet | BottomSheet是一個(gè)從屏幕底部滑起的列表(以顯示更多的內(nèi)容)。你可以調(diào)用showBottomSheet()或showModalBottomSheet彈出 |
SnackBar | 具有可選操作的輕量級(jí)消息提示,在屏幕的底部顯示。 |
Card | 一個(gè) Material Design 卡片。擁有一個(gè)圓角和陰影 |
ListTile | 一個(gè)固定高度的行,通常包含一些文本,以及一個(gè)行前或行尾圖標(biāo)。 |
Divider | 一個(gè)邏輯1像素厚的水平分割線,兩邊都有填充 |
Placeholder | 一個(gè)繪制了一個(gè)盒子的的widget,代表日后有widget將會(huì)被添加到該盒子中 |
RefreshIndicator | 內(nèi)置下拉刷新控件 |
ListView | 可以有多個(gè)子 Widget。 |
負(fù)責(zé)Layout的Widget
Flutter 中擁有需要將近30種內(nèi)置的 布局Widget,其中常用有 Container、Padding、Center、Flex、Stack、Row、Colum等,下面簡(jiǎn)單講解它們的特性和使用。
類型 | 作用特點(diǎn) |
---|---|
Container | 只有一個(gè)子 Widget。默認(rèn)充滿,包含了padding、margin、constraints、color、width、height、decoration、alignment、transform。 |
Padding | 只有一個(gè)子 Widget。只用于設(shè)置Padding,常用于嵌套child,給child設(shè)置padding。 |
Center | 只有一個(gè)子 Widget。只用于居中顯示,常用于嵌套child,給child設(shè)置居中。 |
Stack | 可以有多個(gè)子 Widget。 子Widget堆疊在一起。 |
Colum | 可以有多個(gè)子 Widget。垂直布局。 |
Row | 可以有多個(gè)子 Widget。水平布局。 |
Expanded | 只有一個(gè)子 Widget。在 Colum 和 Row 中充滿。 |
在iOS系統(tǒng)中,我們使用frame來進(jìn)行UI布局,同時(shí)可以通過addChild和removeChild添加或者移除視圖。
但是在Flutter中,Widget 是不可變的,可以傳入一個(gè)函數(shù),該函數(shù)返回一個(gè)子Widget 給父 Widget。并在該函數(shù)中通過一個(gè) 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; }); }),), ],
Flutter中有兩種方式來處理touch:
一是直接傳遞一個(gè)處理事件的方法給Widget;
或者通過GestureDetector來實(shí)現(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 對(duì)象controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 2000)); //非線性動(dòng)畫final CurvedAnimation curvedAnimation = CurvedAnimation(parent: controller,curve: Curves.elasticInOut);// 通過 Tween 對(duì)象 創(chuàng)建 Animation 對(duì)象animation = Tween(begin: 50.0, end: 200.0).animate(curvedAnimation)//Calls the listener every time the value of the animation changes...addListener(() {// 注意:這句不能少,否則 widget 不會(huì)重繪,也就看不到動(dòng)畫效果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í)行動(dòng)畫controller.forward();// 做動(dòng)畫的widgetbody: Center(child: Container(width: animation.value,height: animation.value,decoration: BoxDecoration(color: Colors.redAccent),),),
數(shù)據(jù)交互
Flutter 是支持原生頁(yè)面和 Flutter 頁(yè)面混合開發(fā)的,但是不支持原生組件在Flutter 中使用,原生端有 MethodChannel 來支持 Flutter 對(duì)原生的一些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是一個(gè)回調(diào)函數(shù)
// 把方法聲明為異步方法,通過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; });}
///不帶參數(shù)的路由表跳轉(zhuǎn) Navigator.pushNamed(context, routeName);///跳轉(zhuǎn)新頁(yè)面并且替換,比如登錄頁(yè)跳轉(zhuǎn)主頁(yè) Navigator.pushReplacementNamed(context, routeName);///跳轉(zhuǎn)到新的路由,并且關(guān)閉給定路由的之前的所有頁(yè)面 Navigator.pushNamedAndRemoveUntil(context, '/calendar', ModalRoute.withName('/'));///帶參數(shù)的路由跳轉(zhuǎn),并且監(jiān)聽返回 Navigator.push(context, new MaterialPageRoute(builder: (context) => new NotifyPage())).then((res) { ///獲取返回處理 });
可以看到,Navigator 的 push 返回的是一個(gè) Future,這個(gè)Future 的作用是在頁(yè)面返回時(shí)被調(diào)用的。也就是你可以通過 Navigator 的 pop 時(shí)返回參數(shù),之后在 Future 中可以的監(jiān)聽中處理頁(yè)面的返回結(jié)果。
@optionalTypeArgs static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {return Navigator.of(context).push(route); }
Flutter 的優(yōu)點(diǎn):
● 熱重載(Hot Reload),利用提供的IDE直接保存代碼并重載,手機(jī)或者模擬器立馬就可以看見效果,這一點(diǎn)調(diào)試起來很方便。
● Widget的理念,對(duì)于Flutter來說,手機(jī)應(yīng)用里的所有組件都是Widget,通過可組合的空間集合、豐富的動(dòng)畫庫(kù)以及分層可擴(kuò)展的架構(gòu)實(shí)現(xiàn)了富有感染力的靈活界面設(shè)計(jì)。
● 借助GPU加速的渲染引擎以及高性能本地代碼運(yùn)行時(shí)以達(dá)到跨平臺(tái)設(shè)備的高質(zhì)量用戶體驗(yàn)。
Flutter 的不足:
● 開發(fā)語言是基于Dart, 對(duì)開發(fā)者而言,增加了不少學(xué)習(xí)成本。
● UI布局方面,層次不夠明顯,不那么直接,復(fù)雜化了程序的可讀性。
● Flutter是一種新的框架,目前市面上應(yīng)用和社區(qū)不太成熟,而且支持的庫(kù)不如ReactNative及原生。
● 目前Dart代碼會(huì)AOT編譯到native,不像ReactNative,支持熱更新起來會(huì)很難,但從API的結(jié)構(gòu)設(shè)計(jì)上來看,后期應(yīng)該很快會(huì)實(shí)現(xiàn)熱更新。
● 不能支持原生組件在Flutter中顯示,導(dǎo)致很多組件需要重新開發(fā),不如ReactNative靈活。
● 現(xiàn)在還不支持HTML
● bate版 0.58
總之從Flutter的設(shè)計(jì)理念來看,整體架構(gòu)都是具有革命性的,相比于其他跨平臺(tái)實(shí)現(xiàn)了真正意義的跨平臺(tái),各平臺(tái)體驗(yàn)一致,而且讓用戶體驗(yàn)達(dá)到了最優(yōu),各種UI庫(kù)和組件也在不斷的增加,各種生態(tài)系統(tǒng)和社區(qū)在不斷的完善,對(duì)于以后新的操作系統(tǒng)適配性會(huì)更強(qiáng),如Fuchsia系統(tǒng),非常值得大家了解和學(xué)習(xí),相信不久的將來,會(huì)慢慢成熟起來,成為主流開發(fā)語言。