В документации Flutter для 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;
}
свойство 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));
}
}
Кроме того, вывод этого будет
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, также бессмысленно.
Edit2:
В ответ на ответ @ 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 говорит, что хранить поддерево как часть состояния некорректно, я неполагаю, что есть какая-то причина, по которой это не совсем нормально, и на самом деле они делают это в некоторых обучающих видеороликах Google. Здесь У нее есть поддерево, созданное и удерживаемое как часть состояния.В ее случае 2 StatelessColorfulTile () виджетов.