跟我學flutter:細細品Widget(三)ProxyWidget,InheritedWidget
前言
ProxyWidget作為抽象基類本身沒有任何功能,但他有兩個實現類ParentDataWidget & InheritedElement
原始碼
```bash abstract class ProxyWidget extends Widget {
const ProxyWidget({ Key? key, required this.child }) : super(key: key);
final Widget child; } ```
InheritedWidget
InheritedWidget 用於在樹上向下傳遞資料。
通過BuildContext.dependOnInheritedWidgetOfExactType可以獲取最近的「Inherited Widget」,需要注意的是通過這種方式獲取「Inherited Widget」時,當「Inherited Widget」狀態有變化時,會導致該引用方 rebuild。
通常,為了使用方便會「Inherited Widget」會提供靜態方法of,在該方法中呼叫BuildContext.dependOnInheritedWidgetOfExactType。of方法可以直接返回「Inherited Widget」,也可以是具體的資料。
有時,「Inherited Widget」是作為另一個類的實現細節而存在的,其本身是私有的(外部不可見),此時of方法就會放到對外公開的類上。最典型的例子就是Theme,其本身是StatelessWidget型別,但其內部建立了一個「Inherited Widget」:_InheritedTheme,of方法就定義在上Theme上:
bash
static ThemeData of(BuildContext context) {
final _InheritedTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
final MaterialLocalizations? localizations = Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
final ScriptCategory category = localizations?.scriptCategory ?? ScriptCategory.englishLike;
final ThemeData theme = inheritedTheme?.theme.data ?? _kFallbackTheme;
return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
}
該of方法返回的是ThemeData型別的具體資料,並在其內部首先呼叫了BuildContext.dependOnInheritedWidgetOfExactType。
我們經常使用的「Inherited Widget」莫過於MediaQuery,同樣提供了of方法:
bash
static MediaQueryData of(BuildContext context) {
assert(context != null);
assert(debugCheckHasMediaQuery(context));
return context.dependOnInheritedWidgetOfExactType<MediaQuery>()!.data;
}
原始碼
```bash abstract class InheritedWidget extends ProxyWidget {
const InheritedWidget({ Key? key, required Widget child }) : super(key: key, child: child);
@override InheritedElement createElement() => InheritedElement(this);
@protected bool updateShouldNotify(covariant InheritedWidget oldWidget); }
```
createElement
「Inherited Widget」對應的 Element 為InheritedElement,一般情況下InheritedElement子類不用重寫該方法;
updateShouldNotify
「Inherited Widget」rebuilt 時判斷是否需要 rebuilt 那些依賴它的 Widget;
如下是MediaQuery.updateShouldNotify的實現,在新老Widget.data 不相等時才 rebuilt 那依賴的 Widget。 ```bash @override bool updateShouldNotify(MediaQuery oldWidget) => data != oldWidget.data;
```
依賴了 InheritedWidget 在資料變動的情況下 didChangeDependencies 會被呼叫, 依賴的意思是 使用 return context.dependOnInheritedWidgetOfExactType
() 如果使用context.getElementForInheritedWidgetOfExactType ().widget的話,只會用其中的資料,而不會重新rebuild
bash
@override
InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
return ancestor;
}
@override
InheritedWidget dependOnInheritedWidgetOfExactType({ Object aspect }) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
//多出的部分
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
我們可以看到,dependOnInheritedWidgetOfExactType() 比 getElementForInheritedWidgetOfExactType()多調了dependOnInheritedElement方法,dependOnInheritedElement原始碼如下:
bash
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
可以看到dependOnInheritedElement方法中主要是註冊了依賴關係!看到這裡也就清晰了,呼叫dependOnInheritedWidgetOfExactType() 和 getElementForInheritedWidgetOfExactType()的區別就是前者會註冊依賴關係,而後者不會,所以在呼叫dependOnInheritedWidgetOfExactType()時,InheritedWidget和依賴它的子孫元件關係便完成了註冊,之後當InheritedWidget發生變化時,就會更新依賴它的子孫元件,也就是會調這些子孫元件的didChangeDependencies()方法和build()方法。而當呼叫的是 getElementForInheritedWidgetOfExactType()時,由於沒有註冊依賴關係,所以之後當InheritedWidget發生變化時,就不會更新相應的子孫Widget。
文章內容參考:https://www.jb51.net/article/221012.htm
- 跟我學flutter:細細品Widget(三)ProxyWidget,InheritedWidget
- 跟我學flutter:細細品Widget(一)Widget&Element初識
- 跟我學flutter:Flutter雷達圖表(一)如何使用kg_charts
- 跟我學flutter:我們來舉個例子通俗易懂講解非同步(二)ioslate迴圈機制
- 跟我學flutter:我們來舉個例子通俗易懂講解非同步(一)ioslate
- 跟我學flutter:我們來舉個例子通俗易懂講解dart 中的 mixin
- 跟我學企業級flutter專案:dio網路框架增加公共請求引數&header
- flutter 優秀dio網路攔截視覺化