【发布时间】:2019-06-26 21:50:38
【问题描述】:
颤振documentation for InheritedWidget 说
小部件的基类,可有效地沿树向下传播信息。
要从构建上下文中获取特定类型的继承小部件的最近实例,请使用 BuildContext.inheritFromWidgetOfExactType。
继承的小部件,当以这种方式引用时,会导致消费者 当继承的小部件本身改变状态时重建。
鉴于 Flutter 中的小部件是不可变的,并且在示例代码中......
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor);
}
@override
bool updateShouldNotify(FrogColor old) => color != old.color;
}
颜色属性为final,因此无法重新分配。假设这个小部件就在树的顶部,就像在大多数示例中一样,它什么时候会有用。对于要替换的小部件,必须创建一个新实例。
大概在这样做的地方,将创建一个作为孩子传递的新实例,导致该孩子的后代也重建,创建其孩子的新实例等。
最终还是要重建整棵树。那么使用inheritFromWidgetOfExactType进行的选择性更新是没有意义的,当InheritedWidget的一个实例的数据对于那个实例永远不会改变的时候?
编辑:
这是我不明白的最简单的例子,我可以放在一起。
在此示例中,“更改”位于应用程序根附近的 InheritedWidget/FrogColor 的唯一方法是重建其父级 (MyApp)。这会导致它重建其子代并创建FrogColor 的新实例,并传递一个新的子实例。我没有看到InheritedWidget/FrogColor 的任何其他方式
会像文档中那样改变它的状态
...当继承的小部件本身改变状态时,将导致消费者重建。
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(MyApp());
}
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor);
}
@override
bool updateShouldNotify(FrogColor old) => color != old.color;
}
class MyApp extends StatefulWidget {
// This widget is the root of your application.
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp>
{
@override
Widget build(BuildContext context) {
var random = Random(DateTime.now().millisecondsSinceEpoch);
return FrogColor(
color : Color.fromARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255)),
child:MaterialApp(
title: 'Flutter Demo',
home: Column (
children: <Widget>[
WidgetA(),
Widget1(),
FlatButton(
child:Text("set state",style:TextStyle(color:Colors.white)),
onPressed:() => this.setState((){})
)
]
)
)
);
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return WidgetB();
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Text("SomeText",style:TextStyle(color:FrogColor.of(context).color));
}
}
class Widget1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Widget2();
}
}
class Widget2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Text("SomeText",style:TextStyle(color:FrogColor.of(context).color));
}
}
此外,this的输出是
I/flutter (24881): Ran Build WidgetA
I/flutter (24881): Ran Build WidgetB
I/flutter (24881): Ran Build Widget1
I/flutter (24881): Ran Build Widget2
所以所有子小部件总是被重建。使在inheritFromWidgetOfExactType中完成的注册也毫无意义。
编辑2:
响应 cmets 中的@RémiRousselet 回答,修改上面的示例,类似于
class MyAppState extends State<MyApp>
{
Widget child;
MyAppState()
{
child = MaterialApp(
title: 'Flutter Demo',
home: Column (
children: <Widget>[
WidgetA(),
Widget1(),
FlatButton(
child:Text("set state",style:TextStyle(color:Colors.white)),
onPressed:() => this.setState((){})
)
]
)
);
}
@override
Widget build(BuildContext context) {
var random = Random(DateTime.now().millisecondsSinceEpoch);
return FrogColor(
color : Color.fromARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255)),
child: child
);
}
}
通过存储不应在构建函数之外修改的树来工作,以便在每次重建时将相同的子树传递给 InhertedWidget。这确实有效,只会导致已向 inheritFromWidgetOfExactType 注册的小部件的重建得到重建,而不是其他小部件。
虽然@RémiRousselet 说将子树存储为状态的一部分是不正确的,但我不认为有任何理由认为这是不正确的,事实上他们在一些谷歌教程视频中这样做了。 Here 她创建了一个子树并作为状态的一部分保存。在她的案例中,有 2 个 StatelessColorfulTile() 小部件。
【问题讨论】:
-
另见scoped_model,这也是自定义
InheritedWidget,没有完整的样板代码 -
@George 这个其他答案并没有真正深入我所问的问题。
-
快速错误说明:n = nextInt(max) 返回 0 api.flutter.dev/flutter/dart-math/Random/nextInt.html
标签: dart flutter inherited-widget