Flutter 的設計思想是“一切皆 Widget”馋艺。
一栅干、demo解讀
我們新建一個Flutter項目,默認生成一個demo捐祠,代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
//1碱鳞、MyApp 是一個 StatelessWidget
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
//2 、MyHomePage 是一個 StatefulWidget
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
//3踱蛀、 _MyHomePageState 是一個 State
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
除去控件部分不說窿给,我們的Flutter demo由 StatelessWidget
和 StatefulWidget
和 State
構(gòu)成。
StatelessWidget:處理靜態(tài)的星岗,無狀態(tài)的視圖展示填大。
StatefulWidget:應對有交互,需要動態(tài)變化視覺效果的場景俏橘,例如圖片控件。
通過父View初始化時傳入的靜態(tài)配置圈浇,StatelessWidget就能完全控制其靜態(tài)顯示寥掐。而StatefulWidget還要借助State對象,處理用戶交互和UI變化磷蜀,并體現(xiàn)在UI上召耘。
二、Widget 設計思路和基本原理
Widget褐隆、Element污它、RenderObject
Widget是視圖結(jié)構(gòu)描述,Element是Widget的一個實例化對象庶弃,將Widget樹的變化做了抽象衫贬,能夠只將需要修改的部分同步到真正的RenderObject樹中。
三棵樹設計的好處是提高性能歇攻,RenderObject 的創(chuàng)建是比較耗性能的固惯,涉及到底層的繪制邏輯,而Widget樹每次刷新都會重建缴守,Element樹會跟上次繪制的Element對比看哪些是有變化的葬毫,只對有變化的對象創(chuàng)建對應的RenderObject。
二屡穗、組件
StatelessWidget 和 StatefulWidget
StatelessWidget:處理靜態(tài)的贴捡,無狀態(tài)的視圖展示。
StatefulWidget:應對有交互村砂,需要動態(tài)變化視覺效果的場景烂斋。
通過父View初始化時傳入的靜態(tài)配置,StatelessWidget就能完全控制其靜態(tài)顯示。而StatefulWidget還要借助State對象源祈,處理用戶交互和UI變化煎源,并體現(xiàn)在UI上。
State生命周期
1.創(chuàng)建
- 構(gòu)造:可以接收父View傳遞的數(shù)據(jù)
- initState:會在State插入視圖樹的時候調(diào)用香缺,生命周期只會調(diào)一次手销,可以為變量設置默認值。
- didChangeDependencies:專門處理State對象依賴關(guān)系變化图张。
- build:創(chuàng)建視圖锋拖,經(jīng)過以上步驟,F(xiàn)ramework認為State已經(jīng)準備好祸轮,調(diào)用build方法兽埃,創(chuàng)建一個Widget返回
2.更新
Widget狀態(tài)更新,主要由三個方法觸發(fā)适袜,setState柄错、didChangeDependencies、didUpdateWidget
setState:數(shù)據(jù)改變就通過這個方法告訴Flutter我這里數(shù)據(jù)改變苦酱,需要重建UI售貌,會調(diào)用build方法
didChangeDependencies:系統(tǒng)語言或主題改變時會回調(diào)。
didUpdateWidget:Widget配置關(guān)系發(fā)生變化疫萤,例如父View觸發(fā)重建颂跨,熱重載時會地哦啊用這個方法。
一旦以上方法被調(diào)用扯饶,F(xiàn)lutter會銷毀老的Widget恒削,調(diào)用build方法重建Widget。
3.銷毀
- deactivate:組件的可見狀態(tài)發(fā)生變化會被調(diào)用尾序。頁面切換時钓丰,State對象在視圖樹中發(fā)生變化,需要暫時移除后重新添加蹲诀,會觸發(fā)組件重建斑粱,調(diào)用這個方法。
- dispose:State被永久從視圖樹中移除時調(diào)用脯爪,組件就要銷毀了则北,可以做一些資源回收操作
4. App生命周期監(jiān)聽
WidgetsBindingObserver
官方demo
class AppLifecycleReactor extends StatefulWidget {
const AppLifecycleReactor({ Key key }) : super(key: key);
@override
_AppLifecycleReactorState createState() => _AppLifecycleReactorState();
}
class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
AppLifecycleState _notification;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() { _notification = state; });
}
@override
Widget build(BuildContext context) {
return Text('Last notification: $_notification');
}
}
5.幀數(shù)據(jù)回調(diào)
WidgetsBinding.instance.addPostFrameCallback((_){
print("FrameCallback 單次Frameh繪制回調(diào)"); //只回調(diào)一次
});
WidgetsBinding.instance.addPersistentFrameCallback((_){
print("FrameCallback 實時Frameh繪制回調(diào)"); //每一幀都回調(diào)
});
觸發(fā)setState,就能看到日志痕慢。
參考:
極客時間-Flutter核心技術(shù)與實戰(zhàn)
《Flutter實戰(zhàn)》電子書-基礎組件