(六)flutter入門之widget解惑

首先在介紹flutter之前,我們需要了解一個概念,在dart中的理念是一切皆為對象,而在flutter上,我們的理念是一切皆widget(可以理解為組件),flutter就是谷歌封裝的完善的基于MD風(fēng)格以及ios的Cupertino風(fēng)格的基于dart語言的一套ui組件框架,由于dart作為谷歌新系統(tǒng)的官方指定語言,并且為ios和安卓統(tǒng)一了開發(fā)風(fēng)格,所以我們可以用flutter開發(fā)出跨平臺的app,現(xiàn)在我們從widget開始介紹flutter的組件

widget組件

在flutter中存在兩種widget,一種是存在狀態(tài)改變的StatefulWidget 和無狀態(tài)改變的StatelessWidget ,這里的狀態(tài)是否需要改變對應(yīng)著我們開發(fā)的過程中這個組件是否需要進行動態(tài)的ui更改操作,如果說我們需要更改ui,這時候就需要繼承StatefulWidget 組件了,否則頁面就是個靜態(tài)的ui無法進行更改,當(dāng)然在開發(fā)的過程中,如果確定當(dāng)前頁面是靜態(tài)的,推薦繼承StatelessWidget 組件,因為對于flutter而言,靜態(tài)的頁面渲染的速度比動態(tài)的組件要快一些,并且由于是靜態(tài)ui,渲染一次以后就不會進行更改重新渲染,所以資源的消耗也會更小一些(當(dāng)然,如果怕出意外或者頻繁改動,所有的組件都繼承StatefulWidget 開發(fā),也是可以的,只是博主不推薦),現(xiàn)在我們創(chuàng)建一下這兩個不同的widget,看看到底有什么不同

StatelessWidget :

class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
    );
  }
}

StatefulWidget :

class MyfulWidget extends StatefulWidget {
  @override
  _MyfulWidgetState createState() => _MyfulWidgetState();
}

class _MyfulWidgetState extends State<MyfulWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
    );
  }
}

從上面可以看出來,兩個widget都有build方法,這個build方法就是組件加載ui的方法,我們需要如何布局,組合出當(dāng)前的組件就需要在build方法中開發(fā),唯一的區(qū)別就是build所在的類不同,StatelessWidget 的build方法就在自己的類中,因為當(dāng)前的組件是靜態(tài)組件,只要加載渲染一次即可,所以默認指定了ui布局,就不需要其他操作了,但是StatefulWidget 的build是在createState的方法中創(chuàng)建的state子類中,這個state是flutter的概念,基本上所有的動態(tài)的組件,谷歌的sdk中默認都會指定對應(yīng)的State,而所有的ui加載也好,數(shù)據(jù)變動也好都在這個子類中操作,那么我們的ui需要變動怎么辦呢?這個時候就需要一個方法手動觸發(fā)更改,刷新widget的生命周期(有React開發(fā)經(jīng)驗的應(yīng)該會發(fā)現(xiàn)這點flutter和React很相似,React也是靠綁定組件的狀態(tài),修改狀態(tài)來刷新ui的,所以有經(jīng)驗的童鞋,可以按照React和原生安卓開發(fā)的經(jīng)驗來理解flutter的生命周期,會事半功倍),所以接下來我們學(xué)習(xí)一下widget的生命周期

1768723716-5b188ca549250_articlex.png

從上面可以看出來widget的生命周期大概分為三個階段

  • 初始化(插入渲染樹)

  • 狀態(tài)改變(在渲染樹中存在)

  • 銷毀(從渲染樹種移除)

初始化階段

構(gòu)造函數(shù)
構(gòu)造函數(shù)屬于每個類的入口,肯定是widget的第一個方法,一般我們都認
為構(gòu)造函數(shù)不屬于生命周期的方法,只認為是觸發(fā)生命周期的入口方法
initState
這個方法是widget的初始化方法,我們可以理解為原生安卓開發(fā)的時候Activity的onCreate生命周期,這
個方法在組件創(chuàng)建的時候只會觸發(fā)一次,我們可以在這個方法中調(diào)用一些參數(shù)的初始化操作,以及控制器的
一些監(jiān)聽等,和我們原生開發(fā)的習(xí)慣一樣,可以在這個方法中默認initEvent()方法等其他操作,但是不建
議在這里做耗時操作,否則會影響到組件的加載創(chuàng)建,甚至可能導(dǎo)致崩潰
didChangeDependencies
這個函數(shù)會緊接著在init函數(shù)之后調(diào)用,并且可以調(diào)用并且可以調(diào)用BuildContext.inheritFromWidgetOfExactType,
可能很多人會疑惑這BuildContext.inheritFromWidgetOfExactType有什么作用或者說具體的場景是什么呢?
我們舉一個例子:假設(shè)我們有一個需求,頁面上需要tab切換操作,tab一般需要自定義一個TabController,
但是tab有兩種用法,還可以選擇使用默認的DefaultTabController處理,這樣的話就不需要自定義控制器了,
在默認的控制器中就用到了BuildContext.inheritFromWidgetOfExactType,我們大概看下源碼:
void didChangeDependencies() {
    super.didChangeDependencies();
    _updateTabController();//從這里調(diào)用了BuildContext.inheritFromWidgetOfExactType
    _initIndicatorPainter();
  }

接著我們看看_updateTabController方法:

void _updateTabController() {
    final TabController newController = widget.controller ?? DefaultTabController.of(context);//這里涉及了一個of傳遞上下文的操作
    ...
    }

接下來我們看看這個傳遞上下文的方法

static TabController of(BuildContext context) {
    final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope);//就是這里觸發(fā)了BuildContext.inheritFromWidgetOfExactType
    return scope?.controller;
  }

看到了大概的源碼實現(xiàn),我們大概了解了這個didChangeDependencies生命周期的作用,但是有人會疑惑,BuildContext.inheritFromWidgetOfExactType到底有什么作用呢?這里我的看法是,可以傳遞context使得組件之間可以跨組件獲取數(shù)據(jù)等操作(如果理解有誤或者有不同的看法,歡迎大佬指正)

build
這個生命周期我們一開始也介紹了,用來掛載組件進行最終ui布局渲染使用的,但是由于我們可能存在ui
修改的情況,也就是說,這個函數(shù)不是只觸發(fā)一次的(是否觸發(fā)一次,是看是不是有state決定的,不是當(dāng)前
生命周期決定)

狀態(tài)改變階段

didUpdateWidget
該生命周期一般是我們組件出現(xiàn)了狀態(tài)改變的時候,就會觸發(fā)當(dāng)前函數(shù),在當(dāng)前函數(shù)中,flutter會創(chuàng)建出來
新的widget,然后和舊的狀態(tài)下的widget進行比較,看看有什么屬性不一樣,有什么進行了改變,然后重新
綁定,這個函數(shù)有個比較坑的點,比如我們改動了以后,可能監(jiān)聽的函數(shù)改變了,或者控制器變更了,我們
必須要在當(dāng)前方法進行移除舊的控制器和監(jiān)聽事件,然后重新綁定新的,否則會影響組件運行,我們通過上
面的生命周期圖可以看出來,當(dāng)前函數(shù)調(diào)用完畢以后,就會再次調(diào)用build方法,也就是重新創(chuàng)建組件布局,
所以我們也可以確定每次我們修改完狀態(tài)后,flutter是重新創(chuàng)建widget出來

組件銷毀階段

deactivate
這個是在銷毀之前調(diào)用的生命周期,目前具體的作用博主也沒使用過,不過經(jīng)過測試,當(dāng)前函數(shù)是在組件
還處于可見狀態(tài)下調(diào)用的,在dispose之前調(diào)用
dispose
組件調(diào)用到當(dāng)前函數(shù)的時候,就會觸發(fā)真的移除組件,銷毀對象,移除控制器,取消監(jiān)聽事件等操作,
不過執(zhí)行當(dāng)前函數(shù)代表正在銷毀,可以理解為還沒銷毀完畢,當(dāng)前函數(shù)執(zhí)行完畢以后就是真的銷毀調(diào)用完畢

好了,經(jīng)過上面的生命周期講解,可能大概知道了widget的生命周期以及大概的作用,那么肯定有人會問,widget怎么觸發(fā)狀態(tài)改變呢?在widget中存在setState函數(shù),在這個函數(shù)內(nèi)部可以編寫我們需要改變的時候觸發(fā)的業(yè)務(wù)代碼,當(dāng)此方法調(diào)用的時候,就代表著當(dāng)前的組件需要進行狀態(tài)更改了,即會觸發(fā)組件狀態(tài)改變階段生命周期流程,但是這里我們需要注意的一點是,在flutter中,狀態(tài)改變的可能存在如下兩種

1.當(dāng)前組件內(nèi)部調(diào)用setState方法
2.當(dāng)前組件的父組件調(diào)用了setState方法,當(dāng)前的組件也會調(diào)用狀態(tài)改變重新渲染的流程,孩子組件調(diào)用
狀態(tài)改變的方法并不會觸發(fā)父組件的狀態(tài)改變的方法(據(jù)說新的sdk可能會改動,博主目前沒測試出來)

其他特殊情況

注(博主在使用的過程中也遇到了很多其他的情況,比如):
1.dispose 生命周期可能不會調(diào)用,在調(diào)用完deactivate 周期以后就掛載了新的節(jié)點到組件樹中的情況。
2.didChangeDependencies生命周期一般情況下只有創(chuàng)建的時候會調(diào)用,起初博主以為整個創(chuàng)建的周期的生命周期
都是只會調(diào)用一次,但是后來博主發(fā)現(xiàn)觸發(fā)了組件依賴的InheritedWidget改變的時候,貌似也會觸發(fā)這個
生命周期,具體的原理應(yīng)該就是我們之前看BuildContext.inheritFromWidgetOfExactType有關(guān)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文在此,此處只為學(xué)習(xí) Widget與ElementWidget主要接口Stateless WidgetState...
    lltree閱讀 4,630評論 0 1
  • 國慶后面兩天在家學(xué)習(xí)整理了一波flutter,基本把能擼過能看到的代碼都過了一遍,此文篇幅較長,建議保存(star...
    Nealyang閱讀 4,453評論 1 17
  • 本文主要介紹了Flutter布局相關(guān)的內(nèi)容,對相關(guān)知識點進行了梳理,并從實際例子觸發(fā),進一步講解該如何去進行布局。...
    Q吹個大氣球Q閱讀 10,207評論 6 51
  • iphoneX由于帶有各種傳感器,不得不搞了個劉海屏,各個國產(chǎn)手機也跟了一波風(fēng),手機傳感器塞的很爽,但苦逼的開發(fā)者...
    戰(zhàn)斗力五只鵝閱讀 14,033評論 1 3
  • 細水長流的歲月里 擁有守護。
    JingG閱讀 201評論 0 1

友情鏈接更多精彩內(nèi)容