TextField 和 BLoC - 值未更新或键盘已关闭
TextField and BLoC - value not updated or keyboard dismissed
我想在 Flutter 中结合使用 TextField
和 BLoC package。目的是使 TextField
的内容与 BLoC 的相应 属性 保持同步。
因为 BLoC 基于 BlocBuilder
小部件,它基本上订阅 Stream
并在 Stream
发出新内容时更新和重新呈现所有受影响的子小部件,我想以下方法就足够了:
BlocBuilder<MyCubit, MyState>(
builder: (BuildContext context, MyState state) {
TextFormField(
initialValue: state.model.title,
onChanged: (String value) => myCubit.setTitle(value),
),
}
);
实际上,它正在运行。当我希望能够覆盖来自 BLoC 的值时,问题就出现了。在我的例子中,我有一个 TextField
和一个 select 字段 (DropdownButton
)。当用户 select 使用 DropdownButton
的值时,TextField
的内容应该被覆盖。
使用上述方法,当我在 DropdownButton
的 onChange
中调用 setTitle(value)
时, Cubit
中的值被覆盖,但 TextField
保持不变.
然后我想到使用 TextEditingController
来处理 TextField
的文本(就像 Felix Angelov 建议的 here),更新 Cubit
on change 并监听 Cubit
:
中相应值的外部变化
BlocConsumer<MyCubit, MyState>(
listener: (BuildContext context, MyState state) {
if (state is InitialState) {
_controller.addListener(() {
myCubit.setTitle(_controller.text);
});
return;
}
_controller.text = state.title;
},
builder: (BuildContext context, MyState state) {
TextFormField(
controller: _controller,
),
}
);
如果我这样做,那么初始值由 Cubit
正确设置,当我使用 DropdownButton
更改它时,该值在 TextField
中更新并且它已更新在 TextField
中的文本发生变化时。但是,有一个问题:每次我在 TextField
中输入一个字符时,它就会失去焦点。
autofocus: true
救援?不幸的是没有。这样可以防止失去焦点,但是每当我输入内容时它都会跳转到输入文本的第一个字符。另外,我不希望 TextField
最初具有焦点。设置 FocusNode
也无济于事。
即使像建议的那样设置 UniqueKey
也不会改变什么。
关于FocusNode
和onEditingComplete
的想法也没有解决我的问题。
有没有人有一个 TextField 结合 BLoC 的工作解决方案,可以满足以下要求:
- 当输入
TextField
中的内容时,BLoC/Cubit 会相应更新
- 当 BloC/Cubit 更新时,
TextField
的内容也会相应更新
- 没有意外、烦人的键盘关闭行为或
TextField
失去焦点
TextField
可以有初始值但不一定非得着重渲染
尽管研究了一段时间,但我仍然找不到解决方案。
我认为 TextField
的以下代码是正确的,只是您可以使用 TextEditingController
来设置其初始值。可以在initState
里面设置controller的初始值,所以需要使用stateful widget
@override
void initState() {
super.initState();
final state = BlocProvider.of<MyCubit>(context, listen: false);
_controller = TextEditingController(text: state.model.title);
}
BlocBuilder<MyCubit, MyState>(
builder: (BuildContext context, MyState state) {
TextFormField(
controller: _controller,
onChanged: (String value) => myCubit.setTitle(value),
),
}
);
在 DropdownButton
的 onChanged
中,除了在肘上调用 setTitle(value)
外,还使用其 controller
更改 TextField
的值.
(value){
myCubit.setTitle(value);
_controller.text = value;
}
唯一可能仍未解决的问题是调用 _controller.text = value;
时光标移动到开头 -- 在第一个字符之前。
在您稍后尝试使用 TextEditingController
更改 TextField
文本时,为什么您的 TextField
被包裹在 BlocBuilder
中?我相信这可以正确地从你的 BLoC:
更新 TextField
的文本
BlocListener<MyCubit, MyState>(
listener: (BuildContext context, MyState state) {
if(state.title != _controller.text) {
_controller.text = state.title;
_controller.selection = TextSelection.collapsed(offset: state.title.length);
}
},
child: TextFormField(
controller: _controller,
),
);
为了使用来自 TextField
的事件更新 BLoC 内部的值,请在 initState
.
中注册 TextEditingController
的侦听器
@override
void initState() {
super.initState();
_controller.addListener(_changed);
}
@override
void dispose() {
_controller.removeListener(_changed);
super.dispose();
}
_changed() {
myCubit.setTitle(_controller.text);
}
我想在 Flutter 中结合使用 TextField
和 BLoC package。目的是使 TextField
的内容与 BLoC 的相应 属性 保持同步。
因为 BLoC 基于 BlocBuilder
小部件,它基本上订阅 Stream
并在 Stream
发出新内容时更新和重新呈现所有受影响的子小部件,我想以下方法就足够了:
BlocBuilder<MyCubit, MyState>(
builder: (BuildContext context, MyState state) {
TextFormField(
initialValue: state.model.title,
onChanged: (String value) => myCubit.setTitle(value),
),
}
);
实际上,它正在运行。当我希望能够覆盖来自 BLoC 的值时,问题就出现了。在我的例子中,我有一个 TextField
和一个 select 字段 (DropdownButton
)。当用户 select 使用 DropdownButton
的值时,TextField
的内容应该被覆盖。
使用上述方法,当我在 DropdownButton
的 onChange
中调用 setTitle(value)
时, Cubit
中的值被覆盖,但 TextField
保持不变.
然后我想到使用 TextEditingController
来处理 TextField
的文本(就像 Felix Angelov 建议的 here),更新 Cubit
on change 并监听 Cubit
:
BlocConsumer<MyCubit, MyState>(
listener: (BuildContext context, MyState state) {
if (state is InitialState) {
_controller.addListener(() {
myCubit.setTitle(_controller.text);
});
return;
}
_controller.text = state.title;
},
builder: (BuildContext context, MyState state) {
TextFormField(
controller: _controller,
),
}
);
如果我这样做,那么初始值由 Cubit
正确设置,当我使用 DropdownButton
更改它时,该值在 TextField
中更新并且它已更新在 TextField
中的文本发生变化时。但是,有一个问题:每次我在 TextField
中输入一个字符时,它就会失去焦点。
autofocus: true
救援?不幸的是没有。这样可以防止失去焦点,但是每当我输入内容时它都会跳转到输入文本的第一个字符。另外,我不希望 TextField
最初具有焦点。设置 FocusNode
也无济于事。
即使像建议的那样设置 UniqueKey
FocusNode
和onEditingComplete
的想法也没有解决我的问题。
有没有人有一个 TextField 结合 BLoC 的工作解决方案,可以满足以下要求:
- 当输入
TextField
中的内容时,BLoC/Cubit 会相应更新 - 当 BloC/Cubit 更新时,
TextField
的内容也会相应更新 - 没有意外、烦人的键盘关闭行为或
TextField
失去焦点 TextField
可以有初始值但不一定非得着重渲染
尽管研究了一段时间,但我仍然找不到解决方案。
我认为 TextField
的以下代码是正确的,只是您可以使用 TextEditingController
来设置其初始值。可以在initState
里面设置controller的初始值,所以需要使用stateful widget
@override
void initState() {
super.initState();
final state = BlocProvider.of<MyCubit>(context, listen: false);
_controller = TextEditingController(text: state.model.title);
}
BlocBuilder<MyCubit, MyState>(
builder: (BuildContext context, MyState state) {
TextFormField(
controller: _controller,
onChanged: (String value) => myCubit.setTitle(value),
),
}
);
在 DropdownButton
的 onChanged
中,除了在肘上调用 setTitle(value)
外,还使用其 controller
更改 TextField
的值.
(value){
myCubit.setTitle(value);
_controller.text = value;
}
唯一可能仍未解决的问题是调用 _controller.text = value;
时光标移动到开头 -- 在第一个字符之前。
在您稍后尝试使用 TextEditingController
更改 TextField
文本时,为什么您的 TextField
被包裹在 BlocBuilder
中?我相信这可以正确地从你的 BLoC:
TextField
的文本
BlocListener<MyCubit, MyState>(
listener: (BuildContext context, MyState state) {
if(state.title != _controller.text) {
_controller.text = state.title;
_controller.selection = TextSelection.collapsed(offset: state.title.length);
}
},
child: TextFormField(
controller: _controller,
),
);
为了使用来自 TextField
的事件更新 BLoC 内部的值,请在 initState
.
TextEditingController
的侦听器
@override
void initState() {
super.initState();
_controller.addListener(_changed);
}
@override
void dispose() {
_controller.removeListener(_changed);
super.dispose();
}
_changed() {
myCubit.setTitle(_controller.text);
}