我正在使用Bloc库,并注意到在产生新状态后,我的TextFormField
initialValue没有改变。
我的应用程序比这更复杂,但我做了一个最小的例子。还跟踪它在推送事件后的状态变化。
Bloc应该正确地重建整个小部件。我错过了什么吗?
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:developer' as developer;
void main() {
runApp(MyApp());
}
enum Event { first }
class ExampleBloc extends Bloc<Event, int> {
ExampleBloc() : super(0);
@override
Stream<int> mapEventToState(Event event) async* {
yield state + 1;
}
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (_) => ExampleBloc(),
child: Builder(
builder: (contex) => SafeArea(
child: BlocConsumer<ExampleBloc, int>(
listener: (context, state) {},
builder: (context, int state) {
developer.log(state.toString());
return Scaffold(
body: Form(
child: Column(
children: [
TextFormField(
autocorrect: false,
initialValue: state.toString(),
),
RaisedButton(
child: Text('Press'),
onPressed: () {
context.bloc<ExampleBloc>().add(Event.first);
},
)
],
),
),
);
}),
),
),
),
);
}
}
pubspec.yaml
name: form
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
bloc: ^6.0.0
flutter_bloc: ^6.0.0
编辑
正如@chunhunghan所指出的,添加一个UniqueKey解决了这个问题。我还应该提到我的情况。应用程序从两个TextFormField
的onChanged
方法发出事件。这会导致窗体重置并删除键盘。自动对焦不起作用,因为有两个TextFormField
wgich发出事件。
4条答案
按热度按时间anauzrmj1#
你可以复制粘贴运行完整的代码1和2下面
您可以将
UniqueKey()
提供给Scaffold
或TextFormField
以强制重新创建有关详细信息,请参阅https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
如果元素的键与相应的Widget的键不匹配,则返回。这会导致Flutter停用这些元素并删除对元素树中元素的引用
解决方案1:
解决方案二:
工作演示
完整代码1
Scaffold
与UniqueKey
完整代码2
TextFormField
与UniqueKey
q3aa05252#
您不应该仅仅因为要更新
TextFormField
的值而重建整个Form
,请尝试使用TextEditingController
并更新侦听器上的值。bvjxkvbb3#
我也遇到了同样的问题。在添加
Unique Key
的同时,flutter一直在构建小部件,每次我的键盘都没有焦点。我解决这个问题的方法是在TextField的onChanged事件中添加一个去抖动。希望如果这对某人有帮助,与形式,块和工作也更新了形式。
编辑:虽然添加了一个反跳帮助显示什么。我已经改变了代码更健壮。这里是变化。
InputTextWidget
(已更改)在我的演讲结束时
这个编辑工作得很好。
最终编辑:
我在我的块状态下添加了一个
key? key
,并将此键传递给小部件。如果我需要重新绘制表单,我将事件中的键更改为UniqueKey
。这是迄今为止我实现块和表单的最简单方法。如果您需要解释,请在这里评论,我稍后会添加它。nszi6y054#
正确的做法:
1.创建一个承载表单的有状态小部件。这是确保TextEditingControllers不会在rebuild =〉时被释放/新创建的必要条件。它确保状态被保留。
1.为每个TextFormField创建一个TextEditingController并传递它
1.加载数据后,仅设置TextEditingController的值一次。
1.使用TextFormField方法(onChanged、onFieldSubmitted)更新Bloc的状态,以保持TextEditingController和您的状态同步。
1.如果你有一些后端生成的值或调整,请确保更新,只有这样,TextEditingControllers与值。例如,再次触发初始Loading-Flow,或切换状态。
请记住,理解自己的BLoc逻辑/流程以及TextEditingController如何工作是绝对关键的。如果您不断更新TextEditingController,光标将跳转,因为设置文本将触发setState,从而导致新的构建调用。处理此问题的方法是在更改后设置选择,但如果您搞砸了BLoc,请注意。你将再次在跳跃的光标和键盘中结束。我的建议是退后一步,在一张纸上画出流程来获得概述。否则你将继续与框架作战。
本示例中的BLoC具有以下状态:
在“保存”之后,我用更新的记录将我的状态更新回就绪状态,并且BlocConsumer的侦听器将再次被触发,然后将更新TextEditingController。
TL:DR传入一个TextEditingController,只对真正需要重建的部分使用BlocBuilder,不要使用任何密钥破解。
实现示例:
游标设置示例,例如更新后: