本篇文章主要介绍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
类
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<Counter>();
}
@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: <Widget>[
const Text(
'You have pushed the button this many times:',
),
WidgetE(),
],
),
),
));
}
@override
Widget build(BuildContext context) {
return buildInheritedWidget(context);
}
运转结果如下
接下来,咱们创立一个有状况的InheritedWidget
有状况的InheritedWidget
1,创立一个持有状况的InheritedWidget
。
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<CounterWidget>();
}
@override
bool updateShouldNotify(covariant CounterWidget oldWidget) {
// TODO: implement updateShouldNotify
return oldWidget.counter != counter;
}
}
- 1,比较于无状况的,这儿新增了一个
CounterWrapperState
。
解下来,创立一个StatefulWidget
,并将CounterWidget
作为该部件的子部件。
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<CounterWidget>())!.data
: context.findAncestorWidgetOfExactType<CounterWidget>()!.data;
}
@override
CounterWrapperState createState() => CounterWrapperState();
}
class CounterWrapperState extends State<CounterWrapper> {
int counter = 0;
void incrementCounter() { // 3
setState(() {
counter++;
});
}
@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
:
/// 使计数状况改动
class WidgetA extends StatefulWidget {
const WidgetA({Key? key}) : super(key: key);
@override
_WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
@override
Widget build(BuildContext context) {
print("A refresh");
return ElevatedButton(onPressed: onPressed, child: Text("Increment"));
}
onPressed() {
CounterWrapperState wrapper = CounterWrapper.of(context, build: false);
wrapper.incrementCounter();
}
}
/// 部分改写
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
假如觉得有收成请按如下方式给个
爱心三连
::点个赞鼓励一下
。:收藏文章,便利回看哦!
。:谈论沟通,相互前进!
。