如何在 Flutter 中将 textEditiing 控制器与 Provider 一起使用

vin*_*ali 10 dart flutter flutter-provider

我正在使用提供程序进行状态管理。我的表单中有多种类型的字段。问题在于文本字段 每当我更改文本时,它的行为都很奇怪,就像输入的文本以相反的顺序显示一样。

class MyProvider with ChangeNotifier{
  String _name;
  String get name => _name;
  setname(String name) {
    _name = name;
    notifyListeners();
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MyProvider myProvider = Provider.of<MyProvider>(context);

    final TextEditingController _nameController = TextEditingController(
        text: myProvider.name,
    );

    return TextField(
        controller: _nameController,
        onChanged: myProvider.setname,
    );

}
Run Code Online (Sandbox Code Playgroud)

Igo*_*din 10

发生这种情况是因为TextEditingController在每次构建小部件时都会创建新实例,并且有关当前光标位置 ( TextEditingValue) 的信息正在丢失。

initState方法中创建一个控制器并在方法中处理它dispose


class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  TextEditingController _nameController;

  @override
  void initState() {
    final MyProvider myProvider = Provider.of<MyProvider>(context, listen: false);

    super.initState();
    _nameController = TextEditingController(text: myProvider.name);
  }

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final MyProvider myProvider = Provider.of<MyProvider>(context);

    return TextField(
        controller: _nameController,
        onChanged: myProvider.setname,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个方法有效,谢谢。我听说,当使用提供程序时,我们可以避免使用有状态小部件,并将其替换为无状态小部件,但这里我们使用的是有状态小部件。这不正确吗? (2认同)
  • @vinayakbhanushali `TextEditingController` 是视图(小部件)的一部分,仅在视图存在时才存在。当小部件存在时,控制器会维护它并且必须将其存储在某个地方。当一个小部件被释放时,一个控制器也应该被释放。因此最好将控制器存储在其小部件附近 - 在其状态下可以将其保存在 Provider 中,但这不是最佳实践,因为控制器与业务逻辑无关。但是,在 Provider 的帮助下,与业务逻辑相关的所有内容都从 widget 状态转移到 Provider 中。 (2认同)