理解InheritedWidget及应用
本篇文章主要介绍Flutter
中的InheritedWidget
小部件,以及其官方小部件库中的应用。
官方介绍
关于InheritedWidget
,在官方文档中是这样描述的:
* 1,可以沿着树向下传递信息。
* 2,可以使用 BuildContext.dependOnInheritedWidgetOfExactType
方法,获取最近的指定类型的inherited widget
。
* 3,当inherited widget
的状态
发生改变时,所有依赖其状态的子部件都会进行rebuild
。
我们该如何理解InheritedWidget
呢,接下来,通过几个示例来阐述InheritedWidget
。
ThemeData
我们经常使用的ThemeData
就是一个inheritedWidget
,通常我们App
的root
为MaterialApp
,这样我们的ThemeData
在Widget
树的最顶端。
我们可以使用
final themeData = Theme.of(context);
来获取当前的主题,当主题改变时,会从Widget
树的最顶端,沿着树,从上到下,依次刷新每个依赖themeData
的子部件。
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));
}
从static ThemeData of(BuildContext context)
的实现我们可以看出其是一个InheritedWidget
。
示例
无状态InheritedWidget
对于无状态的InheritedWidget
,我们以读取其共享的数据为例展开,接下来,我们新建Counter
类
```dart class Counter extends InheritedWidget { // 1 const Counter( {Key? key, required this.child, required this.counter}) : super(key: key, child: child); // 2
final int counter;
final Widget child;
static Counter? of(BuildContext context) { // 3
return context.dependOnInheritedWidgetOfExactType
@override
bool updateShouldNotify(covariant Counter oldWidget) { // 4
return oldWidget.counter != counter;
}
}
``
* 1,
Counter继承
InheritedWidget。
* 2,在构建时,需要提供
counter值和
子Widget`。
* 3,向子部件提供获取状态的接口。
* 4,是否通知子部件进行状态刷新。
我们可以这样使用该InheritedWidget
```
Widget buildInheritedWidget(BuildContext context) {
return Counter(
counter: 5,
child: Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:
}
@override Widget build(BuildContext context) {
return buildInheritedWidget(context); } ``` 运行结果如下
接下来,我们创建一个有状态的InheritedWidget
有状态的InheritedWidget
1,创建一个持有状态的InheritedWidget
。
```dart class CounterWidget extends InheritedWidget { const CounterWidget( {Key? key, required this.counter, required this.child, required this.data}) : super(child: child, key: key);
final int counter;
final Widget child;
final CounterWrapperState data; // 1
/// 获取 CounterWidget 实例
static CounterWidget? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType
@override bool updateShouldNotify(covariant CounterWidget oldWidget) { // TODO: implement updateShouldNotify return oldWidget.counter != counter; } } ```
- 1,相比于无状态的,这里新增了一个
CounterWrapperState
。
解下来,创建一个StatefulWidget
,并将CounterWidget
作为该部件的子部件。
```dart
class CounterWrapper extends StatefulWidget {
final Widget child; // 1
const CounterWrapper({Key? key, required this.child}) : super(key: key);
static CounterWrapperState of(BuildContext context, {bool build = true}) { // 2
return build
? (context.dependOnInheritedWidgetOfExactType
@override CounterWrapperState createState() => CounterWrapperState(); }
class CounterWrapperState extends State
@override
Widget build(BuildContext context) { // 4
return CounterWidget(data: this, counter: counter, child: widget.child);
}
}
``
* 1,在构建时,需提供
child,并传递给
CounterWidget。
* 2,提供获取状态的接口,有两种方式 : 当使用
dependOnInheritedWidgetOfExactType时,当状态改变时,会重新
rebuild子部件。
使用
findAncestorWidgetOfExactType`时,当状态改变时,子部件不会刷新。
- 3,计数器加1,刷新Widget。
- 4,将
CounterWidget
作为CounterWrapper
的子部件。
子Widget刷新、局部刷新、不刷新
接下来,创建5个不同的Widget
:
```dart /// 使计数状态改变 class WidgetA extends StatefulWidget { const WidgetA({Key? key}) : super(key: key);
@override _WidgetAState createState() => _WidgetAState(); }
class _WidgetAState extends State
/// 局部刷新 class WidgetB extends StatelessWidget { const WidgetB({Key? key}) : super(key: key); @override Widget build(BuildContext context) { print("widget B 整个 刷新"); return Builder(builder: (contextTwo) { print("widget B Text 局部刷新"); final CounterWrapperState state = CounterWrapper.of(contextTwo, build: true); return Text('${state.counter}'); }); } }
/// inheritedWidget刷新时,也刷新
class WidgetC extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterWrapperState state =
CounterWrapper.of(context, build: true);
print("widget C 刷新");
return new Text('I am Widget C ${state.counter}');
}
}
/// inheritedWidget刷新时,不刷新
class WidgetC1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterWrapperState state =
CounterWrapper.of(context, build: false);
print("widget C1 刷新");
return new Text('I am Widget C1 ${state.counter}');
}
}
/// 不依赖inheriteWidget状态的子部件
class WidgetD extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("widget D 刷新");
return new Text('I am Widget D');
}
}
``
* 1,**WidgetA:** 使 **CounterWrapper** 的状态改变。
* 2,**WidgetB:** 不刷新整个页面,对依赖部分进行
局部刷新`。
* 3,WidgetC: 依赖inheritedWidget的状态,状态改变时,也随之刷新。
* 4,WidgetC1: 只在初始化时,获取inheritedWidget的状态,不随之刷新。
* 5,WidgetD: inheritedWidget的子部件,但不依赖其状态
我们将这些Widget
加载到视图中
Widget buildStatefulInheritedWidget(BuildContext context) {
return CounterWrapper(
child: Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
WidgetB(),
WidgetA(),
WidgetC(),
WidgetC1(),
WidgetD(),
],
),
),
));
}
界面如下
点击increment
,只会有 WidgetC
和 WidgetB
进行刷新。
flutter: widget C 刷新
flutter: widget B Text 局部刷新
这样我们就可以定义我们自己的inheritedWidget
,并通知其子部件进行数据刷新。
总结
我们可以使用InheritedWidget
共享全局状态,子部件可以获取其状态,并控制小部件刷新
最后附上本文涉及的示例代码 inherited_widget_demo
如果觉得有收获请按如下方式给个
爱心三连
:👍:点个赞鼓励一下
。🌟:收藏文章,方便回看哦!
。💬:评论交流,互相进步!
。
- Dart中的event loop
- Dart并发编程: isolate
- 理解InheritedWidget及应用
- 动态库原理
- Flutter是如何渲染Widget的
- 解码Flutter(三)ListView嵌套
- 解码Flutter(一)
- Flutter设计模式(二)-Builder Pattern
- Flutter设计模式(一)- 抽象工厂模式
- 深入理解Swift中的引用计数
- 超实用~使用Xcode编译Swift源码
- cocoapods-binary工作原理及改进
- 基于Cocaopods工程,快速实现Swift组件二进制
- Xcode13对Swift对象生命周期的优化
- Swift并发编程async/await
- iOS 理解符号多一点
- 在iOS中高效的加载图片
- iOS 列表滑动的卡顿检测和优化
- iOS的渲染循环、离屏渲染原理、卡顿原理
- iOS组件化-Pod库制作的常见问题