Art*_*ine 7 state state-management dart flutter statefulwidget
我正在尝试保留小部件的状态,以便如果我暂时从小部件树中删除有状态小部件,然后稍后重新添加它,小部件将具有与删除之前相同的状态。这是我的一个简化示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showCounterWidget = true;
@override
Widget build(BuildContext context) {
return Material(
child: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showCounterWidget ? CounterButton(): Text("Other widget"),
SizedBox(height: 16,),
FlatButton(
child: Text("Toggle Widget"),
onPressed: (){
setState(() {
showCounterWidget = !showCounterWidget;
});
},
)
],
),
),
);
}
}
class CounterButton extends StatefulWidget {
@override
_CounterButtonState createState() => _CounterButtonState();
}
class _CounterButtonState extends State<CounterButton> {
int counter = 0;
@override
Widget build(BuildContext context) {
return MaterialButton(
color: Colors.orangeAccent,
child: Text(counter.toString()),
onPressed: () {
setState(() {
counter++;
});
},
);
}
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,我不希望状态重置,因此计数器不会重置为 0,我将如何保留计数器小部件的状态?
Rém*_*let 14
正如 Joshua 所说,小部件暂时从树中移除时失去其状态的原因是因为它失去了它的元素/状态。
现在你可能会问:
我不能缓存元素/状态以便下次插入小部件时,它可以重用前一个而不是重新创建它们吗?
这是一个有效的想法,但不是。你不能。Flutter 将其判断为反模式,并会在这种情况下抛出异常。
您应该做的是将小部件保持在小部件树中,处于禁用状态。
为了实现这样的事情,你可以使用小部件,如:
这些小部件将允许您将小部件保留在小部件树中(以保持其状态),但禁用其渲染/动画/语义。
因此,而不是:
Widget build(context) {
if (condition)
return Foo();
else
return Bar();
}
Run Code Online (Sandbox Code Playgroud)
在它们之间切换时,这会使Foo/Bar失去它们的状态
做:
IndexedStack(
index: condition ? 0 : 1, // switch between Foo and Bar based on condition
children: [
Foo(),
Bar(),
],
)
Run Code Online (Sandbox Code Playgroud)
使用此代码,则Foo/Bar会不会做了一回,并将它们之间来回时失去它们的状态。
小部件旨在在其范围和生命周期内存储自己的瞬态数据。
根据您提供的内容,您正在尝试通过将其删除并添加回小部件树来重新创建CounterButton 子部件。
在这种情况下, 下的计数器值CounterButton 未保存或未保存在MyHomePage屏幕、父窗口小部件中,没有任何对视图模型或顶层内或顶层的任何状态管理的引用。
更技术性的概述 Flutter 如何渲染你的 widget
key有没有想过如果您尝试为小部件创建构造函数会发生什么?
class CounterButton extends StatefulWidget {
const CounterButton({Key key}) : super(key: key);
@override
_CounterButtonState createState() => _CounterButtonState();
}
Run Code Online (Sandbox Code Playgroud)
key ( key) 是由 Flutter 框架自动处理和使用的标识符,用于区分 widget 树中的 widget 实例。在控件树中删除和添加控件 ( ) 会重置分配给它的控件,因此它所保存的数据及其状态也会被删除。CounterButtonkey
Widget注意:如果 a 仅包含作为其参数,则无需为 a 创建构造函数key。
从文档中:
通常,作为另一个小部件的唯一子部件的小部件不需要显式键。
为什么 Flutter 会更改分配给 CounterButton 的按键?
你在CounterButtonwhich is aStatefulWidget和Textwhich is a之间切换StatelessWidget,这就是Flutter 识别出两个完全不同的对象的原因。
您始终可以使用 Dart Devtools 来检查更改并切换 Flutter 应用程序的行为。
请密切关注#3a4d2末尾处_CounterButtonState。

这是切换小部件后的小部件树结构。从CounterButton到Text小部件。

您现在可以看到以 ,CounterButton结尾的标识符#31a53与之前的标识符不同,因为这两个小部件完全不同。

你能做什么?
我建议您将运行时更改的数据保存在 中_MyHomePageState,并CounterButton使用回调函数创建一个构造函数来更新调用小部件中的值。
counter_button.dart
class CounterButton extends StatefulWidget {
final counterValue;
final VoidCallback onCountButtonPressed;
const CounterButton({Key key, this.counterValue, this.onCountButtonPressed})
: super(key: key);
@override
_CounterButtonState createState() => _CounterButtonState();
}
class _CounterButtonState extends State<CounterButton> {
@override
Widget build(BuildContext context) {
return MaterialButton(
color: Colors.orangeAccent,
child: Text(widget.counterValue.toString()),
onPressed: () => widget.onCountButtonPressed(),
);
}
}
Run Code Online (Sandbox Code Playgroud)
_counterValue假设您在 中命名了变量_MyHomePageState,您可以像这样使用它:
主页.dart
_showCounterWidget
? CounterButton(
counterValue: _counterValue,
onCountButtonPressed: () {
setState(() {
_counterValue++;
});
})
: Text("Other widget"),
Run Code Online (Sandbox Code Playgroud)
CounterButton此外,此解决方案将帮助您在应用程序的其他部分重用或其他类似的小部件。
我已在dartpad.dev中添加了完整的示例。
Andrew 和 Matt 做了精彩的演讲,介绍了 Flutter 如何在底层渲染小部件:
进一步阅读
| 归档时间: |
|
| 查看次数: |
3961 次 |
| 最近记录: |