從零開始的Flutter之旅: StatelessWidgetgit
從零開始的Flutter之旅: StatefulWidgetgithub
在以前的文章中,介紹了StatelessWidget與StatefulWidget的特性與它們的呈現原理。緩存
這期要聊的是它們的另外一個兄弟InheritedWidget。bash
InheritedWidget是Flutter中的一個很是重要的功能組件,它可以提供數據在widget樹中從上到下進行傳遞。保證數據在不一樣子widget中進行共享。這對於一些須要使用共享數據的場景很是有效,例如,在Flutter SDK中就是經過InheritedWidget來共享應用的主題與語言信息。微信
可能你還有點模糊,別急,下面咱們經過一個簡單的示例來了解InheritedWidget。網絡
相信開始學Flutter時都看過官方的計數器示例。咱們將官方提供的計數器示例使用InheritedWidget進行改造。架構
首先咱們須要一個CountInheritedWidget,它繼承於InheritedWidget。app
class CountInheritedWidget extends InheritedWidget {
CountInheritedWidget({@required this.count, Widget child})
: super(child: child);
// 共享數據,計數的數量
final int count;
// 統一的獲取CountInheritedWidget實例, 方便樹中子widget的獲取共享數據
// 必須在State中調用纔會有效
static CountInheritedWidget of(BuildContext context) {
// 調用共享數據的子widget將不會回調didChangeDependencies方法,即子widget將不會更新
// return context.getElementForInheritedWidgetOfExactType<CountInheritedWidget>().widget;
return context.dependOnInheritedWidgetOfExactType<CountInheritedWidget>();
}
// true -> 通知樹中依賴改共享數據的子widget
@override
bool updateShouldNotify(CountInheritedWidget oldWidget) {
return oldWidget.count != count;
}
}
複製代碼
如今已經有了共享數據count的提供,接下來是在具體的子widget中進行使用。框架
咱們抽離出一個CountText子widgetless
class CountText extends StatefulWidget {
@override
_CountTextState createState() {
return _CountTextState();
}
}
class _CountTextState extends State<CountText> {
@override
Widget build(BuildContext context) {
return Text("count: ${CountInheritedWidget.of(context).count.toString()}");
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("didChangeDependencies");
}
}
複製代碼
最後,咱們再將CountInheritedWidget與CountText結合起來,經過簡單的點擊自增事件來看下效果
class CountWidget extends StatefulWidget {
@override
_CountState createState() {
return _CountState();
}
}
class _CountState extends State<CountWidget> {
int count = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Count App',
theme: new ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(
title: Text("Count"),
),
body: Center(
child: CountInheritedWidget(
count: count,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CountText(),
RaisedButton(
onPressed: () => setState(() => count++),
child: Text("Increment"),
)
],
),
),
),
),
);
}
}
複製代碼
上面的層級關係是CountText恰好是CountInheritedWidget的子widget。
如今咱們經過點擊事件直接改變外部的count值,若是InheritedWidget從上到下數據傳到的效果可以生效,那麼在CountText中引用的count將會與外部count同步,程序呈現的效果將會是自增的,同時因爲依賴的count發生改變CountText中的didChangeDependencies也會回調。
咱們直接運行一下
點擊後的輸出日誌
I/flutter: didChangeDependencies
複製代碼
說明InheritedWidget的效果已經生效,經過InheritedWidget的使用,咱們能夠很方便的在嵌套下層的子widget中拿到上層的數據,或者說整個widget的共享數據。
在依賴方式改變時子widget的didChangeDependencies會回調,但因爲你可能會在該方法中作一些特殊的操做,例如網絡請求。只是須要一次就能夠。若是是套用咱們上面的示例,將會在count子增時反覆調用。
爲了防止didChangeDependencies的調用,咱們再來看CountInheritedWidget的of方法中註釋的那部分
static CountInheritedWidget of(BuildContext context) {
// 調用共享數據的子widget將不會回調didChangeDependencies方法,即子widget將不會更新
// return context.getElementForInheritedWidgetOfExactType<CountInheritedWidget>().widget;
return context.dependOnInheritedWidgetOfExactType<CountInheritedWidget>();
}
複製代碼
咱們使用的是dependOnInheritedWidgetOfExactType方法,依賴的共享數據發生改變時會回調子widget中的didChangeDependencies方法,若是咱們不想要子widget調用該方法,可使用註釋的代碼,經過getElementForInheritedWidgetOfExactType方法來獲取共享數據。
若是此時咱們再運行一下項目,點擊count自增,控制檯將不會再輸出日誌。這樣就能夠解決didChangeDependencies的反覆調用。
而這兩個方法的主要區別是在dependOnInheritedWidgetOfExactType調用的過程當中會進行註冊依賴關係
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
複製代碼
因此dependOnInheritedWidgetOfExactType更新依賴的子widget中的didChangeDependencies方法。
思考下一個問題,雖然如今didChangeDependencies方法不會調用,可是CountText的build方法仍是會執行。緣由是在CountWidget中經過setState來改變count值,會從新build所用的子widget。但咱們真正想要的只是更新子widget中依賴的CountInheritedWidget的組件值。
那麼如何解決呢?這裏提供一個解決方案是爲子widget提供緩存。能夠經過封裝一個簡單的StatefulWidget,將子widget緩存起來。若是對這塊感興趣的,能夠期待個人後續文章。
下面介紹一個完整的Flutter項目,對於新手來講是個不錯的入門。
flutter_github,這是一個基於Flutter的Github客戶端同時支持Android與IOS,支持帳戶密碼與認證登錄。使用dart語言進行開發,項目架構是基於Model/State/ViewModel的MSVM;使用Navigator進行頁面的跳轉;網絡框架使用了dio。項目正在持續更新中,感興趣的能夠關注一下。
固然若是你想了解Android原生,相信flutter_github的純Android版本AwesomeGithub是一個不錯的選擇。
若是你喜歡個人文章模式,或者對我接下來的文章感興趣,建議您關注個人微信公衆號:【Android補給站】
或者掃描下方二維碼,與我創建有效的溝通,同時更快更準的收到個人更新推送。