InheritedWidget是Flutter中非常重要的一個功能型組件,它提供了一種數據在widget樹中從上到下傳遞、共用的方式,比如我們在應用的根widget中通過InheritedWidget共用了一個數據,那麼我們便可以在任意子widget中來獲取該共用的數據。 ...
如需轉載,請註明出處:Flutter學習筆記(27)--數據共用(InheritedWidget)
InheritedWidget是Flutter中非常重要的一個功能型組件,它提供了一種數據在widget樹中從上到下傳遞、共用的方式,比如我們在應用的根widget中通過InheritedWidget共用了一個數據,那麼我們便可以在任意子widget中來獲取該共用的數據。
前言:假設有這麼一個場景,A、B兩個組件,A組件有一個數據data,當A組件中的這個數據data發生變化後,B組件需要跟隨著做一些處理操作,這時候,如果不通過廣播或其他方式通知B組件,我們有什麼辦法實現這個功能呢?
didChangeDependencies
在State對象中,有一個didChangeDependencies回調,這個回調會在“依賴”發生變化時被Flutter Framework調用。而這個“依賴”指的是子widget是否用到了父widget中的InheritedWidget共用數據。如果使用了,則代表子widget依賴InheritedWidget,反之如果沒有使用則代表沒有依賴。這種機制可以使子組件在所依賴的InheritedWidget發生變化時來更新自身。這也就可以實現我們前面所假設的場景了!
接下來先給大家看一下整體的代碼和效果截圖,心裡先有一個大概的概念,帶著幾個概念去思考:1.依賴 2.didChangeDependencies回調 3.InheritedWidge通過什麼來通知子widget
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class FatherWidget extends InheritedWidget { final int data; FatherWidget({@required this.data, Widget child}) : super(child: child); //子樹通過該方法獲取共用數據 static FatherWidget getData(BuildContext context) { return context.inheritFromWidgetOfExactType(FatherWidget); } //該回調決定當data發生變化時,是否通知子樹中依賴data的widget @override bool updateShouldNotify(FatherWidget oldWidget) { return oldWidget.data != data; } } class ChildWidget extends StatefulWidget { @override _ChildWidgetState createState() => _ChildWidgetState(); } class _ChildWidgetState extends State<ChildWidget> { @override Widget build(BuildContext context) { return new Text(FatherWidget.getData(context).data.toString()); } @override void didChangeDependencies() { super.didChangeDependencies(); //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時會被調用 //如果build中沒有依賴InheritedWidget,則此回調不會被調用 print("didChangeDependencies = " + FatherWidget.getData(context).data.toString()); } } class MyApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyAppState(); } } class _MyAppState extends State<MyApp> { int count = 0; @override Widget build(BuildContext context) { return new MaterialApp( title: 'title', home: new Scaffold( appBar: new AppBar( title: new Text('title'), ), body: new Center( child: FatherWidget( data: count, child: new Column( children: <Widget>[ ChildWidget(), new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),), ], ), ), ), ), ); } _changeCount() { setState(() { ++count; print('mCount == ' + count.toString()); }); } }
整體代碼說明:
點擊按鈕後會調用_changeCount()方法,方法內給count數加1,然後通知框架重新build,重新build會給FatherWidget內的data重新賦值,data的數據發生了變化,updateShouldNotify會返回true,通知子widget執行didChangeDependencies回調來處理一下響應操作。
分塊說明一下實現數據共用都需要哪幾步:
1.用於存儲共用數據的父Widget,該widget繼承InheritedWidget
class FatherWidget extends InheritedWidget { final int data; FatherWidget({@required this.data, Widget child}) : super(child: child); //子樹通過該方法獲取共用數據 static FatherWidget getData(BuildContext context) { return context.inheritFromWidgetOfExactType(FatherWidget); } //該回調決定當data發生變化時,是否通知子樹中依賴data的widget @override bool updateShouldNotify(FatherWidget oldWidget) { return oldWidget.data != data; } }
2.子widget,用來處理依賴發生變化時的響應處理操作didChangeDependencies
class ChildWidget extends StatefulWidget { @override _ChildWidgetState createState() => _ChildWidgetState(); } class _ChildWidgetState extends State<ChildWidget> { @override Widget build(BuildContext context) { return new Text(FatherWidget.getData(context).data.toString()); } @override void didChangeDependencies() { super.didChangeDependencies(); //父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時會被調用 //如果build中沒有依賴InheritedWidget,則此回調不會被調用 print("didChangeDependencies = " + FatherWidget.getData(context).data.toString()); } }
3.FahterWidget和ChildWidget產生依賴關係
//子樹通過該方法獲取共用數據 static FatherWidget getData(BuildContext context) { return context.inheritFromWidgetOfExactType(FatherWidget); }
4.數據更新,通過setState來重新build
class MyApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _MyAppState(); } } class _MyAppState extends State<MyApp> { int count = 0; @override Widget build(BuildContext context) { return new MaterialApp( title: 'title', home: new Scaffold( appBar: new AppBar( title: new Text('title'), ), body: new Center( child: FatherWidget( data: count, child: new Column( children: <Widget>[ ChildWidget(), new FloatingActionButton(onPressed: _changeCount,child: new Icon(Icons.adjust),), ], ), ), ), ), ); } _changeCount() { setState(() { ++count; print('mCount == ' + count.toString()); }); } }
最後需要註意一點,上面說到的依賴前提是兩個組件是父、子的關係,我試了一下,如果FatherWidget中沒有ChildWidget,只是單純的使用了FatherWidget的數據的話,是不會觸發didChangeDependencies回調的!!!