跨平臺移動UI框架實踐--Flutter

Google 出品扮休,Dart語言掸哑,F(xiàn)lutter Engine引擎鼻由,響應(yīng)式設(shè)計模式,原生渲染橱赠。

目錄

1.png

1. 什么是Flutter

  • 現(xiàn)有移動平臺:

蘋果的iOS SDKs發(fā)布于2008年尤仍,谷歌的Android軟件開發(fā)工具包發(fā)布于2009年,這兩種sdk包是基于不同的編程語言的狭姨,分別是Objective-C和Java, 如下是大概的結(jié)構(gòu)圖:


2.jpg
  • 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繪制。

3.jpg

得益于 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)

4.jpg

如上圖,F(xiàn)lutter 主要分為 Framework 和 Engine飞傀,我們基于Framework 開發(fā)App皇型,運行在 Engine 上。Engine 是 Flutter 的獨立虛擬機砸烦,由它適配和提供跨平臺支持弃鸦。

3. 使用Flutter進行開發(fā)

5.png
6.png

在Flutter中,幾乎所有東西都是一個widget - 甚至布局模型都是widget幢痘。您在Flutter應(yīng)用中看到的圖像唬格、圖標和文本都是widget。 甚至你看不到的東西也是widget颜说,例如行(row)购岗、列(column)以及用來排列、約束和對齊這些可見widget的網(wǎng)格门粪。

  1. Widgets
  • Widget生命周期

    Flutter提供兩種類型的Widget, StatelessWidget 和 StatefulWidget喊积,前者為狀態(tài)不可變,后者可以通過setState()改變state來改變更新UI玄妈,開發(fā)者可以根據(jù)自己的實際情況使用
    StatefulWidget:


    7.jpg

    StatelessWidget:

    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 中充滿墨辛。
  1. 布局方式

在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;
          });
        }),
     ),
],
  1. 事件監(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 分解事件按鈕'),
         ),
       ),
  1. 動畫
 // 創(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
         ),
       ),
     ),
  1. 數(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ù)
  1. 網(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;
      });
 }
  1. 路由導(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

  1. 內(nèi)存對比
9.png
  1. 啟動速度
    10.jpg
  1. 包大小對比
    11.jpg
  1. 兼容性對比
    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é)

  1. Flutter 的優(yōu)點:

    ● 熱重載(Hot Reload),利用提供的IDE直接保存代碼并重載碟绑,手機或者模擬器立馬就可以看見效果俺猿,這一點調(diào)試起來很方便。
    ● Widget的理念蜈敢,對于Flutter來說辜荠,手機應(yīng)用里的所有組件都是Widget,通過可組合的空間集合抓狭、豐富的動畫庫以及分層可擴展的架構(gòu)實現(xiàn)了富有感染力的靈活界面設(shè)計伯病。
    ● 借助GPU加速的渲染引擎以及高性能本地代碼運行時以達到跨平臺設(shè)備的高質(zhì)量用戶體驗。

  1. 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ā)語言丸卷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市询刹,隨后出現(xiàn)的幾起案子谜嫉,更是在濱河造成了極大的恐慌,老刑警劉巖凹联,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沐兰,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔽挠,警方通過查閱死者的電腦和手機住闯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人比原,你說我怎么就攤上這事插佛。” “怎么了量窘?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵雇寇,是天一觀的道長。 經(jīng)常有香客問我蚌铜,道長锨侯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任厘线,我火速辦了婚禮识腿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘造壮。我一直安慰自己,他們只是感情好骂束,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布耳璧。 她就那樣靜靜地躺著,像睡著了一般展箱。 火紅的嫁衣襯著肌膚如雪旨枯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天混驰,我揣著相機與錄音攀隔,去河邊找鬼。 笑死栖榨,一個胖子當著我的面吹牛昆汹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播婴栽,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼满粗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了愚争?” 一聲冷哼從身側(cè)響起映皆,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轰枝,沒想到半個月后捅彻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡鞍陨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年步淹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡贤旷,死狀恐怖广料,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幼驶,我是刑警寧澤艾杏,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站盅藻,受9級特大地震影響购桑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氏淑,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一勃蜘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧假残,春花似錦缭贡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眶俩,卻和暖如春莹汤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颠印。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工纲岭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人线罕。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓止潮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親闻坚。 傳聞我的和親對象是個殘疾皇子沽翔,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 2017終于過去~~看過那些意外的表演,才知道一切不過如此窿凤,都是注定的必然仅偎;擁抱那些意外的溫暖,才明白世間仍有愛意...
    溫小暖000閱讀 259評論 0 1
  • 今天雨過天晴了雳殊,天空尉藍漂著白云橘沥,空氣特別清爽,雖然是周六夯秃,但是公司人員都在積極工作座咆,沒有懈怠痢艺。感恩我能擁有這...
    雪域紅梅閱讀 228評論 0 0
  • 為構(gòu)建山東特色家庭教育服務(wù)體系,開創(chuàng)家庭教育工作新局面介陶,5月6日至7日堤舒,省家庭教育專家指導(dǎo)委員會暨省教育學(xué)會家庭...
    長跑人閱讀 639評論 0 1