flutter系列InheritedWidget介绍
InheritedWidget介紹
在Flutter進(jìn)行界面開發(fā)時(shí),我們經(jīng)常會(huì)遇到數(shù)據(jù)傳遞的問題。由于Flutter采用節(jié)點(diǎn)樹的方式組織頁(yè)面,以致于一個(gè)普通頁(yè)面的節(jié)點(diǎn)層級(jí)會(huì)很深。此時(shí),我們?nèi)绻€是一層層傳遞數(shù)據(jù),當(dāng)需要獲取多層父節(jié)點(diǎn)的數(shù)據(jù)時(shí),會(huì)非常麻煩。 因?yàn)槌霈F(xiàn)上述問題,Flutter給我我們提供一種InheritedWidget,InheritedWidget能夠讓節(jié)點(diǎn)下的所有子節(jié)點(diǎn),訪問該節(jié)點(diǎn)下的數(shù)據(jù)。 關(guān)于Scoped Model、BloC、Provider就是基于InheritedWidget實(shí)現(xiàn)的。
InheritedWidget源碼分析
可以看到InheritedWidget的源碼非常簡(jiǎn)單。
/// 抽象類,繼承自Proxywidget 繼承路徑InheritedWidget => ProxyWidget => Widget abstract class InheritedWidget extends ProxyWidget {/// 構(gòu)造函數(shù)/// 因?yàn)镮nheritedWidget是沒有界面的Widget,所有需要傳入實(shí)際的Widget const InheritedWidget({ Key key, Widget child }): super(key: key, child: child);/// 重寫了超類Widget createElement方法@overrideInheritedElement createElement() => InheritedElement(this);/// 父級(jí)或祖先widget中改變(updateShouldNotify返回true)時(shí)會(huì)被調(diào)用。@protectedbool updateShouldNotify(covariant InheritedWidget oldWidget); }InheritedWidget示例
import 'package:flutter/material.dart'; import 'package:flutter_code/InheritedWidget/InheritedState.dart';class InheritedCount extends StatefulWidget {@override_InheritedCountState createState() => _InheritedCountState(); }class _InheritedCountState extends State<InheritedCount> {int _count = 0;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("InheritedDemo"),),floatingActionButton: FloatingActionButton(onPressed: () {setState(() {_count++;});},child: Icon(Icons.add, color: Colors.white,),),body: Center(child: InheritedState(count: _count,child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround,crossAxisAlignment: CrossAxisAlignment.center,children: [WidgetA(),WidgetB()],)),),);} }class WidgetA extends StatelessWidget {@overrideWidget build(BuildContext context) {return Text("widget text");} }class WidgetB extends StatelessWidget {@overrideWidget build(BuildContext context) {return Text(InheritedState.of(context)?.count.toString(),style: TextStyle(color: Colors.green,fontSize: 50), );} } import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';class InheritedState extends InheritedWidget {/// 構(gòu)造方法InheritedState({Key key,@required this.count,@required Widget child}): assert(count != null),super(key:key, child: child);/// 需要共享的數(shù)據(jù)final int count;/// 獲取組件最近當(dāng)前的InheritedWidgetstatic InheritedState of(BuildContext context) {return context.dependOnInheritedWidgetOfExactType<InheritedState>();}/// 通知依賴該樹共享數(shù)據(jù)的子widget@overridebool updateShouldNotify(covariant InheritedState oldWidget) {return count != oldWidget.count;}}InheritedWidget源碼分析
在上面的計(jì)數(shù)器示例代碼中,WidgetB和InheritedWidget發(fā)生關(guān)聯(lián)的就是InheritedState.of(context)?.count.toString(),其中最關(guān)鍵的方式是context.dependOnInheritedWidgetOfExactType(),我們查看dependOnInheritedWidgetOfExactType()在Element中的源碼如下:該代碼是在framework.dart 第3960行
Map<Type, InheritedElement> _inheritedWidgets;@overrideT dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {/// 斷言,用于在調(diào)試狀態(tài)下檢測(cè)是否有正在使用(激活)的祖先assert(_debugCheckStateIsActiveForAncestorLookup());/// 獲取到_inheritedWidgets數(shù)組數(shù)據(jù)final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];if (ancestor != null) {// 斷言,判斷當(dāng)前ancestor是否是InheritedElement類型assert(ancestor is InheritedElement);// 返回并調(diào)用更新方法return dependOnInheritedElement(ancestor, aspect: aspect) as T;}_hadUnsatisfiedDependencies = true;return null;}我們不難看出,每一個(gè)Element實(shí)例都會(huì)持有一個(gè)_inheritedWidgets,調(diào)用次用該方法時(shí)會(huì)從改集合對(duì)象中取出相關(guān)類型的InheritedElement實(shí)例,那么在這個(gè)方法中我們沒有看到設(shè)置_inheritedWidgets的方法,我們來查看一下_inheritedWidgets是如何賦值的。
// Element void _updateInheritance() {assert(_active);_inheritedWidgets = _parent?._inheritedWidgets;}我們找到賦值是在_updateInheritance方法中,首先斷言當(dāng)前節(jié)點(diǎn)是否激活,然后通過父節(jié)點(diǎn)的_inheritedWidgets進(jìn)行賦值,我們繼續(xù)來看_updateInheritance什么情況下會(huì)調(diào)用:
@mustCallSupervoid mount(Element parent, dynamic newSlot) {......_updateInheritance();......}@mustCallSupervoid activate() {......_updateInheritance();......}我們可以看到在Element中它在mount和activate函數(shù)執(zhí)行了調(diào)用,也就是說element每次掛載和重新時(shí),會(huì)調(diào)用該方法。那么當(dāng)該方法執(zhí)行的時(shí)候,element就會(huì)從上層中拿到所有的InheritedElement。而InheritedElement他最終繼承了Element,并可以看到InheritedElement重寫了_updateInheritance方法:
@overridevoid _updateInheritance() {assert(_active);final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;if (incomingWidgets != null)_inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);else_inheritedWidgets = HashMap<Type, InheritedElement>();_inheritedWidgets[widget.runtimeType] = this;}InheritedWidget是如何進(jìn)行刷新的
前面我們分析到InheritedElement會(huì)拿到父類的所有的InheritedElment并向下傳遞,而InheritedWidget正是通過這種方法才能讓下面的子Widget能訪問的上層中所有的InheritedWidget,那么它是如何進(jìn)行刷新的呢?我們?cè)贓lement的dependOnInheritedWidgetOfExactType方法中調(diào)用了dependOnInheritedElement方法,代碼如下:
Set<InheritedElement> _dependencies;@override InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {assert(ancestor != null);_dependencies ??= HashSet<InheritedElement>();_dependencies.add(ancestor);ancestor.updateDependencies(this, aspect);return ancestor.widget; }@protected void updateDependencies(Element dependent, Object aspect) {setDependencies(dependent, null); }@protected void setDependencies(Element dependent, Object value) {_dependents[dependent] = value; }可以看到InheritedElement實(shí)例調(diào)用自己的updateDependencies方法并將當(dāng)前的Element實(shí)例傳遞過去
/// Called during build when the [widget] has changed.////// By default, calls [notifyClients]. Subclasses may override this method to/// avoid calling [notifyClients] unnecessarily (e.g. if the old and new/// widgets are equivalent).@protectedvoid updated(covariant ProxyWidget oldWidget) {notifyClients(oldWidget);}@overridevoid notifyClients(InheritedWidget oldWidget) {assert(_debugCheckOwnerBuildTargetExists('notifyClients'));for (final Element dependent in _dependents.keys) {assert(() {// check that it really is our descendantElement ancestor = dependent._parent;while (ancestor != this && ancestor != null)ancestor = ancestor._parent;return ancestor == this;}());// check that it really depends on usassert(dependent._dependencies.contains(this));notifyDependent(oldWidget, dependent);}} }@protectedvoid notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {dependent.didChangeDependencies();}由于當(dāng)InheritedElement更新時(shí),會(huì)執(zhí)行updated方法,然后繼續(xù)調(diào)用notifyClients,遍歷所有的element并調(diào)用didChangeDependencies方法。
總結(jié)
以上是生活随笔為你收集整理的flutter系列InheritedWidget介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flutter dart Md5加密
- 下一篇: React.js 的 Web 应用场景有