1

我想在 Flutter 中将 aTextFieldBLoC 包结合使用。目的是使内容TextField与 BLoC 的相应属性保持同步。

因为 BLoC 基于一个BlocBuilder小部件,该小部件基本上订阅 aStream并在发出新内容时更新和重新渲染所有受影响的子小部件Stream,所以我认为以下方法就足够了:

BlocBuilder<MyCubit, MyState>(
    builder: (BuildContext context, MyState state) {
        TextFormField(
          initialValue: state.model.title,
          onChanged: (String value) => myCubit.setTitle(value),
        ),
    }
);

实际上,它正在工作。当我希望能够覆盖 BLoC 中的值时,就会出现问题。就我而言,我有一个TextField和一个选择字段 ( DropdownButton)。当用户从 中选择一个值时DropdownButtonTextField应该覆盖 的内容。使用上述方法,当我调用setTitle(value)onChange时,会覆盖DropdownButton中的值,但保持不变。CubitTextField

然后我想到了使用一个TextEditingController处理文本的想法(就像Felix Angelov在这里TextField建议的那样),更新on change并监听对相应值的外部更改:CubitCubit

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,该值会更新,当文本中的文本更改时,它会在 Cubit 中更新。但是,有一个问题:每次我在 中输入一个字符时,它都会失去焦点。 救援?不幸的是没有。这可以防止失去焦点,但是每当我输入内容时它就会跳转到输入文本的第一个字符。另外,我不希望最初有焦点。设置 a也无济于事。即使设置一个喜欢这里建议的东西也不会改变什么。这里提出的想法也没有解决我的问题。TextFieldDropdownButtonTextFieldTextFieldautofocus: trueTextFieldFocusNodeUniqueKeyFocusNodeonEditingComplete

有没有人有一个与 BLoC 结合的 TextField 的工作解决方案,它满足以下要求:

  • 当输入某些TextField内容时,BLoC/Cubit 会相应更新
  • 当 BloC/Cubit 更新时,TextField的内容也会相应更新
  • 没有意外的、烦人的键盘关闭行为或TextField失去焦点
  • 可以有一个初始值,TextField但不必专注于渲染

尽管已经研究了很长时间,但我找不到解决方案。

4

2 回答 2

1

在您以后尝试使用为什么您被包裹在里面来更改TextField文本时?我相信这对于从您的 BLoC 更新 's text 可以正常工作:TextEditingControllerTextFieldBlocBuilderTextField

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,
  ),
);

为了使用来自您的事件更新 BLoC 内部的值,请TextFieldTextEditingController您的initState.

@override
void initState() {
  super.initState();
  _controller.addListener(_changed);
}

@override
void dispose() {
  _controller.removeListener(_changed);
  super.dispose();
}

_changed() {
  myCubit.setTitle(_controller.text);
}
于 2021-10-19T07:11:00.277 回答
0

我认为下面的代码 forTextField是正确的,只是你可以使用 aTextEditingController来设置它的初始值。您可以在内部设置控制器的初始值initState,因此您需要使用有状态的小部件。

@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),
        ),
    }
);

在 的onChangedDropdownButton,除了调用cubit 外,还可以使用其setTitle(value)更改 的值。TextFieldcontroller

(value){
    myCubit.setTitle(value);
    _controller.text = value;
}

唯一可能仍未解决的问题是当调用_controller.text = value;光标移动到开头时——在第一个字符之前。

于 2021-10-19T07:06:28.737 回答