Flutter documentation for InheritedWidget说
鉴于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;
}
color属性为final
,因此无法重新分配。像大多数示例中一样,假定此小部件位于树的顶部,何时才有用。为了替换小部件,必须创建一个新实例。大概是在这样做的情况下,也会创建一个作为子对象传递的新实例,从而导致该子对象的后代也重建,为其子对象创建新实例等。
最终,整棵树都重建了。因此,当InheritedWidget实例的数据永远不会更改时,使用
inheritFromWidgetOfExactType
进行的选择性更新毫无意义?编辑:
这是我无法理解的最简单的例子。
在此示例中,“更改”靠近应用程序根目录的
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));
}
}
此外,此输出是I/flutter (24881): Ran Build WidgetA
I/flutter (24881): Ran Build WidgetB
I/flutter (24881): Ran Build Widget1
I/flutter (24881): Ran Build Widget2
因此,所有子窗口小部件始终会被重建。使注册在heritFromFromWidgetOfExactType中完成也毫无意义。编辑2:
为了回应评论中的@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。这确实起作用,仅导致重建已继承InheritedFromWidgetOfExactType注册的窗口小部件,而不重建其他窗口小部件。尽管@RémiRousselet表示将子树存储为状态的一部分是不正确的,但我不认为有任何理由认为这是不正确的,实际上他们在某些Google教程视频中这样做。 Here她创建了一个子树并将其保留为该州的一部分。在她的情况下2个StatelessColorfulTile()小部件。
最佳答案
那就是你困惑的地方
重建小部件不会强制其后代重建。
父级重建时,框架会在内部检查newChild == oldChild
,在这种情况下,子级不会重建。
这样,如果小部件的实例没有更改,或者它覆盖了operator==
,那么在更新其父项时,可能无法重建窗口小部件。
这也是AnimatedBuilder
提供child
属性的原因之一:
AnimatedBuilder(
animation: animation,
builder: (context, child) {
return Container(child: child,);
},
child: Text('Hello world'),
);
这样可以确保在整个动画过程中,child
得以保留,因此不会被重建。导致更加优化的UI。