Flutter知識(shí)點(diǎn)

    1. 級(jí)聯(lián)操作符

    Dart 中 級(jí)聯(lián)操作符 可以返回對(duì)象從而繼續(xù)執(zhí)行其他方法:

    new Column(
          children: [
            new Container(),
          ]
            ..addAll(List.generate(3, (index) {
              return Container();
            }))
            ..addAll([
              new HorizontalLine(height: 5),
            ]),
        );
    
    1. 一次性執(zhí)行匿名回調(diào)函數(shù)

    Dart 支持一次性執(zhí)行匿名回調(diào)函數(shù)戈稿,如:

    void test() {
      () {
        print('hi');
      }();
    }
    

    也可在組件中運(yùn)用并接收參數(shù),如:

    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        body: new Text((String text) {
          return text;
        }('我是文字')),
    }
    
    1. 可選方法參數(shù)

    Dart 方法可以設(shè)置 參數(shù)默認(rèn)值指定名稱 讶舰。

    比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法鞍盗,這里 branch 不設(shè)置的話,默認(rèn)是 “master” 跳昼。參數(shù)類型 可以指定或者不指定般甲。調(diào)用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");

    1. Assert (斷言)

    assert 只在檢查模式有效庐舟,在開(kāi)發(fā)過(guò)程中欣除,assert(unicorn == null); 只有條件為真才正常,否則直接拋出異常挪略,一般用在開(kāi)發(fā)過(guò)程中历帚,某些地方不應(yīng)該出現(xiàn)什么狀態(tài)的判斷。

    1. 擴(kuò)展

    擴(kuò)展可以給指定類型的數(shù)值增加獲取方法杠娱,如( ScreenUtil 給 num 加的擴(kuò)展):

    extension SizeExtension on num {
      num get w => ScreenUtil().setWidth(this);
    
      num get h => ScreenUtil().setHeight(this);
    
      num get sp => ScreenUtil().setSp(this);
    
      num get ssp => ScreenUtil().setSp(this, allowFontScalingSelf: true);
    }
    

    比如我想獲取一個(gè) ScreenUtil 適配的50寬度值:

    Container(width: 50.w)
    

    等同于:

    Container(width: ScreenUtil().setWidth(50))
    

    從而簡(jiǎn)化了代碼挽牢,提升了開(kāi)發(fā)效率。

    1. runZoned

    可以在自己的區(qū)域中運(yùn)行指定代碼(根據(jù) zoneSpecification 使用 Zone.fork 創(chuàng)建的區(qū)域)摊求,如果代碼出現(xiàn)錯(cuò)誤將拋出全局錯(cuò)誤在 onError:

    runZoned(() {
        runApp(MyApp());
      }, onError: (Object obj, StackTrace stack) {
        print(obj);
        print(stack);
      });
    

    我們通用的錯(cuò)誤信息統(tǒng)計(jì)平臺(tái)如 sentry禽拔,一般都是放在 runZoned 的 onError 內(nèi)。

組件

1. ListView 自動(dòng)內(nèi)邊距

ListView 會(huì)在腳手架中未寫(xiě) AppBar 的情況下自動(dòng)添加 padding 內(nèi)邊距室叉,內(nèi)邊距值是狀態(tài)欄高度

2. Draggable 重繪問(wèn)題

Draggable 的 child 和 feedback 是同一個(gè)組件是每次拖動(dòng)都會(huì)重繪組件睹栖,如果不想被重繪,在組件的 key 給個(gè) GlobalKey即可茧痕。

3. 拿到數(shù)組模型索引

List.generate 可以獲得數(shù)組模型的索引 index野来,length 寫(xiě)數(shù)組模型的長(zhǎng)度即可。

4. 輸入框內(nèi)容被清空

如果出現(xiàn)輸入框內(nèi)容輸入的時(shí)候突然返回到桌面踪旷,回來(lái)的時(shí)候被清空了曼氛,可以嘗試使用 WidgetsBindingObserver 監(jiān)聽(tīng)不可見(jiàn)生命周期,輸入框焦點(diǎn)自動(dòng)取消令野,從而輸入框會(huì)保存原有內(nèi)容舀患。(這個(gè)問(wèn)題在早期 flutter 版本出現(xiàn))

5. 刷新頁(yè)面的指定組件

如果只想刷新某個(gè)頁(yè)面的指定組件可使用 GlobalKey 包裹此組件的 State 類,調(diào)用此組件的時(shí)候傳過(guò)去气破,想刷新的時(shí)候就可以在外面調(diào)用這個(gè) GlobalKey 的 setState 或其他刷新方法了聊浅。

6. 拿特殊滑動(dòng)組件內(nèi)控制器

特殊滑動(dòng)組件如 NestedScrollView 是有內(nèi)外控制器的,普通的賦值 controller 只能拿到外部的滑動(dòng)值现使,想要拿到內(nèi)控制可以在 NestedScrollView 的 body 中類在上下文獲取低匙,調(diào)用上下文的 ancestorWidgetOfExactType


class DataBody extends StatefulWidget {
  @override
  _DataBodyState createState() => _DataBodyState();
}

class _DataBodyState extends State<DataBody> {
  ScrollController pageScrollController;

  Type typeOf<T>() => T;

  @override
  void initState() {
    super.initState();

    PrimaryScrollController primaryScrollController =
        context.ancestorWidgetOfExactType(typeOf<PrimaryScrollController>());

    pageScrollController = primaryScrollController.controller;
  }
}

不過(guò)這個(gè)在 1.12 已被廢棄,新版 Flutter 使用 findAncestorWidgetOfExactType 代替朴下。

功能

1. 無(wú)需上下文路由

自己定義個(gè) NavigatorState 的全局 key 然后賦值到 MaterialApp 的 navigatorKey 就能使用 NavigatorState 的所有功能并無(wú)需上下文努咐。

2. Future 執(zhí)行完成錯(cuò)誤

如果出現(xiàn) Future 執(zhí)行完成錯(cuò)誤可嘗試使用 Completer 的 future,如:

Future<Null> _refreshData() {
  final Completer<Null> completer = new Completer<Null>();

  new Future.delayed(new Duration(seconds: 2), () {
    completer.complete(null);
  });

  return completer.future;
}

3. 調(diào)用方法出現(xiàn) null 錯(cuò)誤

dispose 銷毀某對(duì)象時(shí)在調(diào)用 .dispose 前加個(gè) ? 問(wèn)號(hào)殴胧,可以避免前面的為空導(dǎo)致調(diào)用不到 dispose 方法報(bào)錯(cuò)渗稍。

4. 頁(yè)面狀態(tài)保存

Flutter 中可以通過(guò) mixins AutomaticKeepAliveClientMixin ,然后重寫(xiě) wantKeepAlive 保持住頁(yè)面团滥,記得在被保持住的頁(yè)面 build 中調(diào)用 super.build 竿屹。

5. 手勢(shì)識(shí)別范圍

使用 GestureDetector 范圍只有 child 的設(shè)定顏色或使用區(qū)域才可被觸發(fā),behavior 為 HitTestBehavior.translucent 時(shí)整個(gè) child 會(huì)被觸發(fā)灸姊,InkWell 組件默認(rèn)整個(gè) child 會(huì)被觸發(fā)拱燃。
hitTest 得到一個(gè)包含所有待處理控件列表 HitTestResult
dispatchEvent 進(jìn)行事件分發(fā)并產(chǎn)生競(jìng)爭(zhēng),最終勝利者可以得到事件響應(yīng)權(quán)

如果同一個(gè)區(qū)域內(nèi)有多個(gè)控件都實(shí)現(xiàn)了 handleEvent力惯,那么最后事件應(yīng)該交給誰(shuí)處理呢碗誉?
事件競(jìng)爭(zhēng)只有符合以下兩個(gè)條件之一的召嘶,才可以得到事件的處理權(quán)。

  1. 最后得到直接勝利的控件
  2. 活到最后的控件中排在列表第一位的控件

6. Flutter 手勢(shì)事件主要是通過(guò)競(jìng)技判斷

主要有 hitTest 把所有需要處理的控件對(duì)應(yīng)的 RenderObject 哮缺, 從 childparent 全部組合成列表弄跌,從最里面一直添加到最外層。

然后從隊(duì)列頭的 child 開(kāi)始 for 循環(huán)執(zhí)行 handleEvent 方法尝苇,執(zhí)行 handleEvent 的過(guò)程不會(huì)被攔截打斷铛只。

一般情況下 Down 事件不會(huì)決出勝利者,大部分時(shí)候是在 Move 或者 up 的時(shí)候才會(huì)決出勝利者糠溜。

競(jìng)技場(chǎng)關(guān)閉時(shí)只有一個(gè)的就直接勝出響應(yīng)淳玩,沒(méi)有勝利者就拿排在隊(duì)列第一個(gè)強(qiáng)制勝利響應(yīng)。

同時(shí)還有 didExceedDeadline 處理按住時(shí)的 Down 事件額外處理非竿,同時(shí)手勢(shì)處理一般在 GestureRecognizer 的子類進(jìn)行蜕着。

插件開(kāi)發(fā)

1. android 獲取 context 和 activity

可以在插件的 Plugin 類實(shí)現(xiàn) ActivityAware,然后在 onAttachedToActivity 和 onReattachedToActivityForConfigChanges 都可以拿到 ActivityPluginBinding 的 binding汽馋,binding 調(diào)用getActivity侮东。


public class DemoPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {

    static Context ctx;
    static Activity activity;

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        ctx = binding.getApplicationContext();
    }

    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        activity = binding.getActivity();
        ctx = binding.getActivity();
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {

    }

    @Override
    public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
        ctx = binding.getActivity();
        activity = binding.getActivity();
    }
}

2. PlatformView

Flutter 中通過(guò) PlatformView 可以嵌套原生 ViewFlutter UI 中,這里面其實(shí)是使用了 Presentation + VirtualDisplay + Surface 等實(shí)現(xiàn)的豹芯,大致原理就是:

使用了類似副屏顯示的技術(shù)悄雅,VirtualDisplay 類代表一個(gè)虛擬顯示器,調(diào)用 DisplayManagercreateVirtualDisplay() 方法铁蹈,將虛擬顯示器的內(nèi)容渲染在一個(gè) Surface 控件上宽闲,然后將 Surface 的 id 通知給 Dart,讓 engine 繪制時(shí)握牧,在內(nèi)存中找到對(duì)應(yīng)的 Surface 畫(huà)面內(nèi)存數(shù)據(jù)容诬,然后繪制出來(lái)。實(shí)時(shí)控件截圖渲染顯示技術(shù)沿腰。

3. Platform Channel

Flutter 中可以通過(guò) Platform Channel 讓 Dart 代碼和原生代碼通信的:

  • BasicMessageChannel:用于傳遞字符串和半結(jié)構(gòu)化的信息览徒。
  • MethodChannel:用于傳遞方法調(diào)用(method invocation)。
  • EventChannel: 用于數(shù)據(jù)流(event streams)的通信颂龙。

同時(shí) Platform Channel 并非是線程安全的
更多詳細(xì)可查閱閑魚(yú)技術(shù)的 《深入理解Flutter Platform Channel》

介紹

1. 運(yùn)行模式

Flutter 的 Debug 下是 JIT 模式习蓬,release 下是 AOT 模式。目前主流的語(yǔ)言大多數(shù)只支持其中一種編譯方式措嵌,如 C 僅支持 AOT躲叼,JavaScript 僅支持 JIT,一般來(lái)說(shuō)靜態(tài)語(yǔ)言使用 AOT企巢,動(dòng)態(tài)語(yǔ)言使用 JIT

AOT 編譯方式下枫慷,編譯器必須在執(zhí)行代碼前將代碼編譯成機(jī)器執(zhí)行的原生代碼,在程序運(yùn)行時(shí)就不需要做其他額外的操作直接快速執(zhí)行,但是編譯時(shí)需要區(qū)分用戶機(jī)器架構(gòu)或听,生成不同架構(gòu)的二進(jìn)制代碼

JIT 程序運(yùn)行前不需要編譯代碼探孝,而是在運(yùn)行時(shí)動(dòng)態(tài)編譯,不用考慮用戶機(jī)器是什么架構(gòu)神帅,雖然縮短了開(kāi)發(fā)周期再姑,但是可能導(dǎo)致程序執(zhí)行速度更慢

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萌抵,一起剝皮案震驚了整個(gè)濱河市找御,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绍填,老刑警劉巖霎桅,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異讨永,居然都是意外死亡滔驶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)卿闹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)揭糕,“玉大人,你說(shuō)我怎么就攤上這事锻霎≈牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵旋恼,是天一觀的道長(zhǎng)吏口。 經(jīng)常有香客問(wèn)我,道長(zhǎng)冰更,這世上最難降的妖魔是什么产徊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮蜀细,結(jié)果婚禮上舟铜,老公的妹妹穿的比我還像新娘。我一直安慰自己奠衔,他們只是感情好谆刨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著涣觉,像睡著了一般痴荐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上官册,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天生兆,我揣著相機(jī)與錄音,去河邊找鬼。 笑死鸦难,一個(gè)胖子當(dāng)著我的面吹牛根吁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播合蔽,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼击敌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拴事?” 一聲冷哼從身側(cè)響起沃斤,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎刃宵,沒(méi)想到半個(gè)月后衡瓶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牲证,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年哮针,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坦袍。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡十厢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捂齐,到底是詐尸還是另有隱情蛮放,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布辛燥,位于F島的核電站筛武,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏挎塌。R本人自食惡果不足惜徘六,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望榴都。 院中可真熱鬧待锈,春花似錦、人聲如沸嘴高。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拴驮。三九已至春瞬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間套啤,已是汗流浹背宽气。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萄涯。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓绪氛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親涝影。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枣察,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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