gpt4 book ai didi

flutter - 从 StatefulWidget 外部控制状态

转载 作者:IT老高 更新时间:2023-10-28 13:48:41 38 4
gpt4 key购买 nike

我正在尝试了解在该 Widget 状态之外控制 StatefulWidget 状态的最佳实践。

我定义了以下接口(interface)。

abstract class StartupView {
Stream<String> get onAppSelected;

set showActivity(bool activity);
set message(String message);
}

我想创建一个实现此接口(interface)的 StatefulWidget StartupPage。我希望小部件执行以下操作:

  1. 当一个按钮被按下时,它会通过 onAppSelected 流发送一个事件。 Controller 甚至会监听并执行一些操作(数据库调用、服务请求等)。

  2. Controller 可以调用 showActivityset message 让 View 通过消息显示进度。

由于 Stateful Widget 不会将其 State 作为属性公开,因此我不知道访问和修改 State 属性的最佳方法。

我希望使用它的方式是这样的:

Widget createStartupPage() {
var page = new StartupPage();
page.onAppSelected.listen((app) {
page.showActivity = true;
//Do some work
page.showActivity = false;
});
}

我曾考虑通过在 createState() 中传入我希望它返回的状态来实例化 Widget,但感觉不对。

我们为什么采用这种方法的一些背景知识:我们目前有一个 Dart Web 应用程序。为了 View Controller 分离、可测试性和对 Flutter 的前瞻性思考,我们决定为应用程序中的每个 View 创建一个接口(interface)。这将允许 WebComponent 或 Flutter Widget 实现此接口(interface)并保持所有 Controller 逻辑相同。

最佳答案

有多种方式可以与其他有状态小部件进行交互。

1. findAncestorStateOfType

第一个也是最直接的方法是通过context.findAncestorStateOfType方法。

通常包装在 Stateful 的静态方法中像这样的子类:

class MyState extends StatefulWidget {
static of(BuildContext context, {bool root = false}) => root
? context.findRootAncestorStateOfType<_MyStateState>()
: context.findAncestorStateOfType<_MyStateState>();

@override
_MyStateState createState() => _MyStateState();
}

class _MyStateState extends State<MyState> {
@override
Widget build(BuildContext context) {
return Container();
}
}

这就是 Navigator例如工作。

亲:

  • 最简单的解决方案

缺点:

  • 想访问 State属性或手动调用setState
  • 需要公开State子类

当你想访问一个变量时不要使用这个方法。当该变量更改时,您的小部件可能不会重新加载。

<强>2。 Listenable、Stream 和/或 InheritedWidget

有时您可能想要访问某些属性而不是方法。问题是,您很可能希望您的小部件在该值随时间变化时更新。

在这种情况下,飞镖报价StreamSink .并且 flutter 添加在它的顶部InheritedWidgetListenableValueNotifier .它们都做相对相同的事情:订阅值更改事件时与 StreamBuilder 结合使用。/context.dependOnInheritedWidgetOfExactType/AnimatedBuilder .

当您想要 State 时,这是首选解决方案暴露一些属性。我不会涵盖所有的可能性,但这里有一个使用 InheritedWidget 的小例子:

首先,我们有一个 InheritedWidget暴露一个 count :

class Count extends InheritedWidget {
static of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<Count>();

final int count;

Count({Key key, @required Widget child, @required this.count})
: assert(count != null),
super(key: key, child: child);

@override
bool updateShouldNotify(Count oldWidget) {
return this.count != oldWidget.count;
}
}

然后我们有我们的State实例化这个 InheritedWidget

class _MyStateState extends State<MyState> {
int count = 0;

@override
Widget build(BuildContext context) {
return Count(
count: count,
child: Scaffold(
body: CountBody(),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
count++;
});
},
),
),
);
}
}

最后,我们有了 CountBody获取这个暴露的count

class CountBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(Count.of(context).count.toString()),
);
}
}

优点:

  • findAncestorStateOfType 更高效
  • Stream 替代方案仅适用于 dart(适用于网络)并且与语言高度集成(关键字如 await forasync*)
  • 当值改变时自动重新加载子项

缺点:

  • 更多样板
  • 流可能很复杂

3.通知

而不是直接调用 State 上的方法,您可以发送Notification从您的小部件。并制作State订阅这些通知。

Notification 的示例将是:

class MyNotification extends Notification {
final String title;

const MyNotification({this.title});
}

要发送通知,只需调用 dispatch(context)在您的通知实例上,它会冒泡。

MyNotification(title: "Foo")..dispatch(context)

Note: you need put above line of code inside a class, otherwise no context, can NOT call notification.

任何给定的小部件都可以使用 NotificationListener<T> 收听其子级发送的通知:

class _MyStateState extends State<MyState> {
@override
Widget build(BuildContext context) {
return NotificationListener<MyNotification>(
onNotification: onTitlePush,
child: Container(),
);
}

bool onTitlePush(MyNotification notification) {
print("New item ${notification.title}");
// true meaning processed, no following notification bubbling.
return true;
}
}

例如 Scrollable ,可以调度ScrollNotification包括开始/结束/过度滚动。然后被 Scrollbar 使用无需访问 ScrollController 即可了解滚动信息

优点:

  • 很酷的响应式(Reactive) API。我们不直接在 State 上做事.它是 State订阅由其子级触发的事件
  • 多个小部件可以订阅同一个通知
  • 防止 child 访问不需要的 State属性

缺点:

  • 可能不适合您的用例
  • 需要更多样板文件

关于flutter - 从 StatefulWidget 外部控制状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46057353/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com