gpt4 book ai didi

flutter - 为什么软件键盘会在打开/关闭时导致小部件重建?

转载 作者:行者123 更新时间:2023-12-03 14:35:40 35 4
gpt4 key购买 nike

我有一个屏幕,其中包含一个 FormStreamBuilder .当我从 StreamBuilder 加载初始数据时, TextFormField按预期显示数据。
当我点击 TextFormField ,软件键盘出现,这会导致小部件重建。当键盘再次按下时,同样的情况再次发生。
不幸的是,StreamBuilder再次订阅,文本框值被替换为初始值。
这是我的代码:

@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: _bloc.inputObservable(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return TextFormField(
// ...
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
);
}
我该如何解决这个问题?

最佳答案

导致重建的键盘
它使 总感预计软件键盘打开导致重建。在幕后,MediaQueryupdated with view insets .这些 MediaQueryData.viewInsets确保您的 UI 知道键盘遮挡了它。抽象地说,遮挡屏幕的键盘会导致窗口发生变化,并且大部分时间会导致您的 UI 发生变化,这需要对 UI 进行更改 - 重建。
我可以自信地猜测您正在使用 Scaffold 在您的 Flutter 应用程序中。像许多其他框架小部件一样,Scaffold小部件 取决于 (参见 InheritedWidget )在 MediaQuery 上(从包含您的应用程序的 Window 获取其数据)使用 MediaQuery.of(context) .
MediaQueryData 想要查询更多的信息。

这一切都归结为 Scaffold依赖于 View 插入。这允许它调整大小 当这些 查看插图 改变。基本上,当键盘打开时, View 插入更新,这允许脚手架在底部收缩,去除被遮挡的空间。
长话短说,适应调整后的 View 插入的脚手架需要重新构建脚手架 UI。并且由于您的小部件必然是脚手架的子项(可能是 body ),因此您的小部件也会在发生这种情况时重建。
您可以使用 Scaffold.resizeToAvoidBottomInset 禁用 View 插入调整大小行为.但是,这不一定会停止重建,因为可能仍然依赖于 MediaQuery .我将在下面解释你应该如何真正思考这个问题。
幂等构建方法
您应该始终以 build 的方式构建您的 Flutter 小部件。方法是 幂等 .
范例是构建调用可以在任何时间点发生,每秒最多 60 次(如果刷新率更高,则可能更多)。
我所说的幂等构建调用的意思是,当您的小部件配置(在 StatelessWidget s 的情况下)或您的状态(在 StatefulWidget s 的情况下)没有任何变化时,生成的小部件树应该是 完全一样 .因此,您不想处理 build 中的任何状态。 - 它的唯一职责应该是代表当前的配置或状态。

导致重建的软件键盘打开只是一个很好的例子,说明为什么会这样。其他示例是旋转设备、在 Web 上调整大小,但随着您的小部件树开始变得复杂,它实际上可以是任何东西(更多内容见下文)。StreamBuilder重新订阅重建
回到最初的问题:在这种情况下,您的问题是您正在接近 StreamBuilder不正确。您应该不是 给它一个流 重新创建 每个构建。
流构建器的工作方式是订阅初始流,然后在流更新时重新订阅。这意味着当 stream StreamBuilder 的属性(property)两个小部件不同 build调用,流构建器将取消订阅第一个流并订阅第二个(新)流。
您可以在 _StreamBuilderBaseState.didUpdateWidget implementation 中看到这一点:

if (oldWidget.stream != widget.stream) {
if (_subscription != null) {
_unsubscribe();
_summary = widget.afterDisconnected(_summary);
}
_subscribe();
}
这里显而易见的解决方案是您需要提供 同一流 当您不想重新订阅时,在不同的构建调用之间。这可以追溯到幂等构建调用!

一个 StreamController例如将始终返回相同的流,这意味着使用 stream: streamController.stream 是安全的。在您的 StreamBuilder .基本上,所有 Controller 、行为主体等实现都应该以这种方式运行 - 只要您不是 重建您的信息流, StreamBuilder会好好照顾的!
因此,您的情况下的错误功能是 _bloc.inputObservable() ,它每次都会创建一个新流,而不是返回相同的流。
笔记
请注意,我说过构建调用可以“在任何时间点”发生。实际上,您可以(技术上)准确控制应用程序中的每个构建何时发生。然而,一个普通的应用程序会非常复杂,以至于你无法控制它,因此,你会希望有幂等的构建调用。
导致重建的键盘就是一个很好的例子。
如果您从高层次考虑,这正是您想要的 - 框架及其小部件(或您创建的小部件)负责响应外部更改并在必要时进行重建。树中的叶小部件不应该关心是否发生了重建——它们应该被放置在任何环境中,并且框架通过相应地重建来负责对该环境的变化使用react。
我希望我能够为你解决这个问题:)

关于flutter - 为什么软件键盘会在打开/关闭时导致小部件重建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56313800/

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