什么是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)