Flutter開發(fā)1:Widget與生命周期

什么是Widget

Flutter中幾乎所有的對象都是一個Widget,這與原生開發(fā)中“控件”概念稍有不同竭宰,F(xiàn)lutter中的Widget表示一切與UI框架相關(guān)的對象空郊,例如:手勢檢測 GestureDetector,而原生開發(fā)中的Widget控件通常僅僅指UI布局中的各種控件切揭,不包含F(xiàn)lutter中的功能型Widget狞甚。

標識符:Key

Flutter 是響應式框架,每次刷新 UI 的時候廓旬,都會重新構(gòu)建新的 Widget樹哼审,并和之前的 Widget樹進行對比,計算出變化的部分嗤谚,這個計算過程就是diff棺蛛,在 diff 過程中,如果能提前知道哪些 Widget 沒有變化巩步,就能提高 diff 的性能旁赊,這時候就需要使用到標識符。

給 Widget 添加一個唯一的標識符椅野,然后在 Widget樹 的 diff 過程中查看刷新前后的 Widget樹终畅,如果標識符相同籍胯,則說明 Widget 沒有變化,否則說明 Widget 有變化离福。

這個標識符就是Flutter 中的Key屬性杖狼,所有 Widget 都有 Key 屬性

Key有兩種類型:

  • Local Key(局部Key)
  • Global Key(全局Key)

什么是StatelessWidget

它是一個比較簡并繼承自Widget類的一個類,常在build方法中通過嵌套其它Widget來構(gòu)建UI妖爷。當我們需要組合并封裝多個Widget控件蝶涩,且不需要維護數(shù)據(jù)狀態(tài)時,可以自定義Widget并繼承該類絮识。它最大的特點是僅表示當前一幀的頁面绿聘,當頁面動態(tài)變化時,每次都會重建數(shù)據(jù)次舌。

需要注意熄攘,它的內(nèi)部成員變量是immutable的,通常需要使用final修飾彼念。

什么是 StatefulWidget

它也是繼承自Widget類挪圾,不同的是一個StatefulWidget類就會對應一個State類。State表示與其對應的StatefulWidget要維護的狀態(tài)逐沙,且State中存在與原生開發(fā)中類似的生命周期回調(diào)哲思。

State 類有兩個功能:

  • build() 方法創(chuàng)建 UI
  • setState() 方法刷新 UI

調(diào)用setState()方法并在其中修改數(shù)據(jù)的值,會觸發(fā) State 的 build() 方法酱吝,重建 Widget也殖,重建時會重新綁定數(shù)據(jù),這時數(shù)據(jù)已變化务热,從而達到更新頁面的目的忆嗜。

State 中還有三個重要的成員變量

  • widget 通過該變量可訪問 StatefulWidget 中定義的成員屬性
  • context 用于獲取當前 StatefulWidget 中的上下文
  • mounted 判斷當前 State 是否已加載到樹中。在State 對象創(chuàng)建之后崎岂,initState() 調(diào)用之前捆毫,框架會將 State 對象加載到樹中,此時 mounted 會變?yōu)?true冲甘,當 State dispose 之后绩卤,mounted 就為 false。因此江醇,在setState() 調(diào)用前可判斷 mounted 的值以避免異常濒憋,mounted 為 false 時調(diào)用setState()會報錯。
if(mounted){
    setState((){
        // :TODO
    })
}

StatelessWidget 和 StatefulWidget的區(qū)別

  • StatelessWidget 是 UI 不可變化的 Widget陶夜,創(chuàng)建完后 UI 就不能發(fā)生變化凛驮;
  • StatefulWidget 是 UI 可變化的 Widget,并存在生命周期条辟,創(chuàng)建完后 UI 可以更改黔夭。通常的宏胯,一個單獨頁面的根Widget應當使用StatefulWidget 包裹,存在并需要封裝動畫時本姥,也需要使用StatefulWidget封裝控件肩袍。

widget生命周期回調(diào)

StatefulWidget 生命周期回調(diào)

  • initState 當Widget 第一次插入到 Widget樹時被調(diào)用,對于每一個State對象婚惫,該回調(diào)只會調(diào)用一次氛赐,所以通常會在回調(diào)中做一些初始化。覆寫此方法時辰妙,應在調(diào)用super.iniState()之后
  • didChangeDependencies 創(chuàng)建時在initState 之后被調(diào)用鹰祸,或者當State對象的依賴發(fā)生變化時調(diào)用甫窟,子類很少覆寫
  • build 構(gòu)建該Widget 表示的UI元素密浑。此方法在不同情況下被調(diào)用:
    1.調(diào)用initState之后
    2.調(diào)用didUpdateWidget之后
    3.調(diào)用setState之后
    4.當State對象的依賴更改(didChangeDependencies)之后
    5.當State對象從樹中一個位置移除后(調(diào)用deactivate)又重新插入到樹的其它位置時調(diào)用
  • didUpdateWidget 當Widget 的狀態(tài)發(fā)生改變時調(diào)用,例如調(diào)用setState
  • deactivate 當State對象從樹中被移除時粗井,會調(diào)用此回調(diào)尔破。如果移除后沒有重新插入到樹中則緊接著會調(diào)用dispose方法,如果覆寫此方法浇衬,應在調(diào)用super.deactivate()之前
    dispose 當State對象從樹中被永久移除時調(diào)用懒构。通常在此回調(diào)中釋放資源,如果覆寫此方法耘擂,應在調(diào)用super.dispose()之前
class _MyHomePageState extends State<MyHomePage> {
//定義變量區(qū)域
  final GlobalKey _gk = GlobalKey();
  int count = 0;

//定義其他函數(shù)胆剧,放前面或者后面都可以
  void _showHint() {

  }

//widget生命周期函數(shù)如下
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    debugPrint('initState');
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    debugPrint('didChangeDependencies');
  }

  @override
  Widget build(BuildContext ctx) {
    // this.context;
    return Scaffold();
  }

  @override
  void didUpdateWidget(covariant MyHomePage oldWidget) {
    super.didUpdateWidget(oldWidget);
    debugPrint('didUpdateWidget');
  }

  @override
  void deactivate() {
    super.deactivate();
    debugPrint('deactivate');
  }

  @override
  void dispose() {
    super.dispose();
    debugPrint('dispose');
  }
}

App 的生命周期

除了Widget,App本身也存在生命周期醉冤,這類似原生App的生命周期秩霍,主要指進入app,按home鍵等系統(tǒng)級的操作蚁阳。

要監(jiān)聽系統(tǒng)級的App生命周期回調(diào)铃绒,需要在頁面的State類上混入WidgetsBindingObserver類,并實現(xiàn)didChangeAppLifecycleState回調(diào)方法
注意:不要忘了注冊和移除監(jiān)聽器螺捐,否則不生效

class _MyAppState extends State<MyApp> with WidgetsBindingObserver{

  @override
  void initState() {
    super.initState();
    /// 注冊監(jiān)聽器
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        break;
      case AppLifecycleState.inactive: 
        break;
      case AppLifecycleState.paused: 
        break;
      case AppLifecycleState.detached: 
        break;
    }
  }

  @override
  void dispose() {
    /// 移除監(jiān)聽器
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

AppLifecycleState提供四種狀態(tài)

  • resumed 應用處于前臺颠悬,可見可交互
  • inactive應用處于非活動狀態(tài)。在 iOS 上定血,當在通話赔癌、響應TouchID請求、進入應用切換器或控制中心時澜沟,應用會過渡到這個狀態(tài)灾票。在Android上,當其他活動被聚焦時倔喂,例如分屏應用铝条、電話呼叫靖苇、畫中畫應用、彈出系統(tǒng)對話框時班缰,應用會過渡到這個狀態(tài)
  • paused應用不可見贤壁,處于后臺運行時處于該狀態(tài)
  • detached Flutter引擎第一次初始化時正在加載視圖,或在視圖因Navigator.pop 而被摧毀后時埠忘,處于該狀態(tài)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脾拆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子莹妒,更是在濱河造成了極大的恐慌名船,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旨怠,死亡現(xiàn)場離奇詭異渠驼,居然都是意外死亡,警方通過查閱死者的電腦和手機鉴腻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門迷扇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人爽哎,你說我怎么就攤上這事蜓席。” “怎么了课锌?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵厨内,是天一觀的道長。 經(jīng)常有香客問我渺贤,道長雏胃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任癣亚,我火速辦了婚禮丑掺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘述雾。我一直安慰自己街州,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布玻孟。 她就那樣靜靜地躺著唆缴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黍翎。 梳的紋絲不亂的頭發(fā)上面徽,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音,去河邊找鬼趟紊。 笑死氮双,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的霎匈。 我是一名探鬼主播戴差,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铛嘱!你這毒婦竟也來了暖释?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤墨吓,失蹤者是張志新(化名)和其女友劉穎球匕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帖烘,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡亮曹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚓让。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乾忱。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖历极,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衷佃,我是刑警寧澤趟卸,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站氏义,受9級特大地震影響锄列,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惯悠,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一邻邮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧克婶,春花似錦筒严、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筋岛,卻和暖如春娶视,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工肪获, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒙保,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓晶乔,卻偏偏與公主長得像辉川,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寒锚,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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