InheritedWidget
概述
在Flutter進(jìn)行界面開(kāi)發(fā)時(shí),我們經(jīng)常會(huì)遇到數(shù)據(jù)傳遞的問(wèn)題惩阶。由于Flutter采用節(jié)點(diǎn)樹(shù)的方式組織頁(yè)面,以致于一個(gè)普通頁(yè)面的節(jié)點(diǎn)層級(jí)會(huì)很深扣汪。此時(shí)断楷,我們?nèi)绻€是一層層傳遞數(shù)據(jù),當(dāng)需要修改數(shù)據(jù)時(shí)崭别,就會(huì)比較麻煩冬筒。
此時(shí),我們需要一種機(jī)制茅主,能夠讓某一個(gè)節(jié)點(diǎn)下的所有子節(jié)點(diǎn)舞痰,訪問(wèn)該節(jié)點(diǎn)下的數(shù)據(jù)。
InheritedWidget就滿足了我們這一需求诀姚。
使用方法
我們創(chuàng)建一個(gè)繼承InheritedWidget
的Widget响牛。
class MyInheritedWidget extends InheritedWidget {
final int data;
MyInheritedWidget(@required this.data, Widget child) : super(child: child);
static MyInheritedWidget getData(BuildContext context) {
return context.inheritFromWidgetOfExactType(MyInheritedWidget);
}
@override
bool updateShouldNotify(MyInheritedWidget oldWidget) {
return oldWidget.data != data;
}
}
可以看到,我們提供了三個(gè)方法赫段。
構(gòu)造方法
InheritedWidget本身是一個(gè)沒(méi)有界面的Widget娃善,或者說(shuō)是一個(gè)代理Widget,我們需要傳入我們實(shí)際的Widget瑞佩。
所以聚磺,在構(gòu)造方法中,我們需要傳入兩個(gè)參數(shù)炬丸,一個(gè)是我們希望共享的數(shù)據(jù)(在本例中數(shù)據(jù)是int型瘫寝,實(shí)際業(yè)務(wù)中共享的通常是一個(gè)相對(duì)復(fù)雜的數(shù)據(jù))蜒蕾,另一個(gè)就是我們帶界面的Widget。
數(shù)據(jù)獲取方法
static MyInheritedWidget getData(BuildContext context) {
return context.inheritFromWidgetOfExactType(MyInheritedWidget);
}
我們看一下inheritFromWidgetOfExactType
方法的源碼:
/// Obtains the nearest widget of the given type, which must be the type of a
/// concrete [InheritedWidget] subclass, and registers this build context with
/// that widget such that when that widget changes (or a new widget of that
/// type is introduced, or the widget goes away), this build context is
/// rebuilt so that it can obtain new values from that widget.
/// The [aspect] parameter is only used when [targetType] is an
/// [InheritedWidget] subclasses that supports partial updates, like
/// [InheritedModel]. It specifies what "aspect" of the inherited
/// widget this context depends on.
InheritedWidget inheritFromWidgetOfExactType(Type targetType, { Object aspect });
注釋說(shuō)得很清楚焕阿,inheritFromWidgetOfExactType是獲取指定context下的咪啡,最近的指定類(lèi)型的Widget,并且此Widget必須是InheritedWidget的子類(lèi)暮屡。
值得注意的是撤摸,它是一個(gè)靜態(tài)方法。所以褒纲,只要是相同BuildContext
我們即可以在任意子節(jié)點(diǎn)上准夷,通過(guò)這個(gè)靜態(tài)方法,獲取到我們的InheritedWidget
莺掠,然后讀取或修改它的共享數(shù)據(jù)衫嵌。
更新通知
這個(gè)方法,決定了是否通知子節(jié)點(diǎn)中StatefulWidget
的didChangeDependencies
方法是否調(diào)用彻秆。
/// Called when a dependency of this [State] object changes.
///
/// For example, if the previous call to [build] referenced an
/// [InheritedWidget] that later changed, the framework would call this
/// method to notify this object about the change.
///
/// This method is also called immediately after [initState]. It is safe to
/// call [BuildContext.inheritFromWidgetOfExactType] from this method.
///
/// Subclasses rarely override this method because the framework always
/// calls [build] after a dependency changes. Some subclasses do override
/// this method because they need to do some expensive work (e.g., network
/// fetches) when their dependencies change, and that work would be too
/// expensive to do for every build.
@protected
@mustCallSuper
void didChangeDependencies() { }
StatefulWidget的didChangeDependencies
方法就是與InheritedWidget
配合使用的楔绞。只有當(dāng)InheritedWidget
發(fā)生更新并且決定通知時(shí),didChangeDependencies
才會(huì)調(diào)用唇兑。
使用場(chǎng)景
通常酒朵,當(dāng)我們需要在Widget樹(shù),由父節(jié)點(diǎn)向子節(jié)點(diǎn)傳遞數(shù)據(jù)時(shí)扎附,會(huì)使用InheritedWidget
耻讽。一旦某個(gè)節(jié)點(diǎn)的Widget繼承了InheritedWidget
,那么它的子節(jié)點(diǎn)帕棉,不論深度是多少针肥,都可以獲取到繼承了InheritedWidget
的Widget,并取得其中的數(shù)據(jù)成員香伴。
class TextWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return TextWidgetState();
}
}
class TextWidgetState extends State<TextWidget> {
@override
Widget build(BuildContext context) {
print("refresh text");
return Text(
"count : ${MyInheritedWidget.getData(context).data}"
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
//父或祖先widget中的InheritedWidget改變(updateShouldNotify返回true)時(shí)會(huì)被調(diào)用慰枕。
//如果build中沒(méi)有依賴(lài)InheritedWidget,則此回調(diào)不會(huì)被調(diào)用即纲。
print("Dependencies change");
}
}
所以具帮,InheritedWidget
適合做某個(gè)子樹(shù)的數(shù)據(jù)管理Widget。當(dāng)某個(gè)頁(yè)面低斋、模塊或控件依賴(lài)一個(gè)或一組數(shù)據(jù)時(shí)蜂厅。我們可以在其上層,創(chuàng)建一個(gè)繼承了InheritedWidget
的數(shù)據(jù)管理Widget膊畴。
通過(guò)這樣的方式掘猿,至少我們不用對(duì)數(shù)據(jù)進(jìn)行層層傳遞。