目前,开发的flutter
项目中,状态管理库使用是Provider
,Provider
基于 InheritedWidget
组件封装,想要减少日常开发采坑,就不得不去了解 InheritedWidget
组件的工作原理。由于要从源码角度分析 InheritedWidget
组件的工作原理,在阅读本文前,最好对 flutter
的知识有一定了解,这样才能更好的了解,本文所要表达的意思。
- 熟悉
flutter
基本使用。 - 了解
provider
的框架。 - 了解
Widget
和Element
之间关系。 - 了解
Element
在flutter
渲染时方法的调用。
一、 InheritedWidget
本文中用到的生产环境
1.1 InheritedWidget 简述
/// 有效地沿树向下传播信息的 Widget 的基类,子 Widget 要想获取最近特定类型的 InheritedWidget实例,请使用
/// [BuildContext.dependOnInheritedWidgetOfExactType]。子 Widget 以这种方式引用时,当 InheritedWidget 改变状态
/// 时,会重新构建依赖的子 Widget。
abstract class InheritedWidget extends ProxyWidget {
const InheritedWidget({ Key key, Widget child })
: super(key: key, child: child);
@override
InheritedElement createElement() => InheritedElement(this);
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);
复制代码
InheritedWidget
代码很简单,主要有两个方法:
createElement
生成InheritedElement
对象。updateShouldNotify
用于控制当前InheritedWidget
发生变化, 所依赖的Widget
是否需要重建。
1.1.1 BuildContext
从 InheritedWidget
描述可得知,如果子 Widget
需要获取 InheritedWidget
对象,可以通过 BuildContext.dependOnInheritedWidgetOfExactType
获取。看下 BuildContext
类的 dependOnInheritedWidgetOfExactType
。
abstract class BuildContext {
/// 获取给定类型“T”的最近 widget,它必须是具体 [InheritedWidget] 子类的类型,并将此构建上下文注册到该 widget,以便当该 widget 更改时(或引入该类型的新 widget, 或 widget 消失),此构建上下文将被重建,以便它可以从该 widget 获取新值。
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object aspect });
/// 获取与给定类型“T”的最近 widget 对应的 element,该 element 必须是具体 [InheritedWidget] 子类的类型。 如果找不到这样的 element,则返回 null。
/// 调用这个方法是 O(1) 一个小的常数因子。 此方法不会像 [dependOnInheritedWidgetOfExactType] 那样与目标建立关
/// 系。 不应从 [State.dispose] 调用此方法,因为此时 element 树不再稳定。 要从该方法引用祖先,请通过在
/// [State.didChangeDependencies] 中调用 [dependOnInheritedWidgetOfExactType] 来保存对祖先的引用。 使用
/// [State.deactivate] 中的此方法是安全的,每当 widget 从树中移除时都会调用该方法。
InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
}
复制代码
1.2 InheritedWidget 应用
接下来,我们写一个基于 InheritedWidget
组件实现的 计数器
。
1.2.1 CountScope
class CountScope extends InheritedWidget {
const CountScope({this.count, Widget child}) : super(child: child);
final int count;
static CountScope of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CountScope>();
}
@override
bool updateShouldNotify(CountScope oldWidget) {
return oldWidget.count != count;
}
}
复制代码
CountScope
继承 InheritedWidget
of
,子Widget
获取CountScope
对象。[见1.1小节]
updateShouldNotify
当oldWidget.count != count
刷新依赖的widget
。[见1.1小节]
1.2.2 CountWidget
class CountWidget extends StatefulWidget {
const CountWidget({Key key}) : super(key: key);
@override
_CountWidgetState createState() => _CountWidgetState();
}
class _CountWidgetState extends State<CountWidget> {
@override
Widget build(BuildContext context) {
print('_CountWidgetState build');
final int count = CountScope.watch(context).count;
return Container(child: Text('$count', style: Theme.of(context).textTheme.headline4));
}
}
复制代码
CountWidget
调用 CountScope.of(context).count
显示计数结果。
1.2.3 MyHomePage
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
print('_MyHomePageState build');
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
CountScope(count: _counter, child: CountWidget()),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
复制代码
到这里计数器功能差不多就完成了,当我们点击浮动 +
按钮时,计数器的数值会累加,最后可以看到效果就是这样。

© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
喜欢就支持一下吧
相关推荐