【问题标题】:flutter - update TextField/TextEditingController via state (provider/consumer)flutter - 通过状态(提供者/消费者)更新 TextField/TextEditingController
【发布时间】:2020-02-06 23:37:40
【问题描述】:

我在“页面”上有一个 TextField。我有一个 TextEditingController 连接到它。我可以通过以下简单的方法成功设置 TextField 的值:

usernameController.text = '1234';

但是,我需要能够从子页面更改此字段。用例是用户从应用程序内部注销的登录表单。当我返回登录页面时,我希望清除/删除用户名/密码。现在,值仍然存在(显示当前在 usernameController.text 中的任何内容)

总的来说,我正在通过 Provider 管理状态。我可以毫无问题地在我的应用程序的其他地方设置和检索/显示状态。问题在于控制器是通过 initState() 中的 dart 代码设置的。它不是重建的小部件的一部分。

我可以在消费者中设置 TextField 小部件。当子页面中的状态更新时调用构建器(通过调试打印语句确认),但小部件本身不反映状态的新值(它仍然具有旧用户名,并且没有被空白)。

                            Consumer<myAppState>(
                          builder: (context, appState, child) {
                            print("in builder for consumer: ");
                            print(appState.username);
                            return Container(
                                width: 200,
                                child: TextField(
                                  controller: usernameController,
                                  onChanged: (value) => _saveUsername(value),
                                  decoration: InputDecoration(
                                    hintText: 'Username',
                                    prefixIcon: Icon(Icons.account_circle),
                                  ),
                                ));
                          }),

我试过替换

usernameController.text = '1234';

与:

usernameController.text = Provider.of<myAppState>(context, listen: true).username;

但这似乎不起作用。

似乎这个“非纯”小部件(因为控制器正在以编程方式处理)在想要重绘小部件的消费者模型中并不漂亮。

大家有什么想法吗?

谢谢!

【问题讨论】:

  • 你想做什么usernameController.text = Provider.of&lt;myAppState&gt;(context, listen: true).username;
  • @HemanthRaj - 我尝试在 initState() 中进行调用,以便在“登录”页面加载后立即执行。我在文档中没有看到“listen:true”实际上创建了任何类型的监听器,当 notifyListeners() 被调用时会得到通知。我只是在尝试“在黑暗中射击”适应我在其他地方看到的代码。
  • 添加initState 不会成功。您可能需要更新builder 中的值。
  • @HemanthRaj - 我相信我在消费者的构建器中尝试过(设置 usernameController.text = Provider.of(context, listen: true).username;) 并且它抛出了一个异常,因为它是“在重绘已经发生时设置一个标志来重绘一个小部件”或类似的东西。我忘记了确切的术语,但如果有帮助,我可以查一下。
  • 当我尝试在 builder() 中使用 setState() 时发生了关于“重绘”错误的评论。如果我尝试直接分配 usernameController.text 它不会抛出错误,但分配似乎没有发生。有关更多详细信息,请参阅您建议的答案中的 cmets。谢谢!

标签: flutter dart


【解决方案1】:

一种可能的方法是检查在构建器中检查状态和控制器中的值是否匹配并同步它们。

例子:

Consumer<myAppState>(
  builder: (context, appState, child) {
    print("in builder for consumer: ");
    print(appState.username);
    if (usernameController.text != appState.username) { // Or check if appState.username != null or what ever your use case is.
      usernameController.text = appState.username ?? '';
    }
    return Container(
      width: 200,
      child: TextField(
        controller: usernameController,
        onChanged: (value) => _saveUsername(value),
        decoration: InputDecoration(
          hintText: 'Username',
          prefixIcon: Icon(Icons.account_circle),
        ),
      ),
    );
  },
)

希望有帮助!

【讨论】:

  • Consumer&lt;myAppState&gt;( builder: (context, appState, child) { print("in builder for consumer: "); print(appState.username); print(usernameController.text); usernameController.text = appState.username; print('controller after reassignment:'); print(usernameController.text); return Container( width: 200, child: TextField( controller: usernameController, onChanged: (value) =&gt; _saveUsername(value), )); }) 返回...:在消费者的构建器中:...:null ...:1234 ...:重新分配后的控制器:...:1234
  • 我尝试复制和粘贴上面的代码/结果,但它很难看。对于我得到的打印/调试结果... I/flutter (23797): in builder for consumer: I/flutter (23797): null I/flutter (23797): 1234 I/flutter (23797): controller after重新分配:I/flutter (23797): 1234 所以您可以看到 appState.username 为空,usernameController.text 最初为“1234”,即使我尝试将 usernameController 重新分配给 appState.username 的值,它也会忽略重新分配并且仍然显示“1234”。也许尝试将其分配给 NULL 是一个问题?
  • 好的,问题与我在注销过程中设置状态的方式有关。我设置为 NULL... Provider.of(context, listen: false).username = null;但这不起作用(如我上面的调试语句所示)。我将其切换为:Provider.of(context, listen: false).username = '';现在它工作正常。知道为什么将它设置为 null 会阻止它工作(并且它没有抛出任何错误)吗?你不能将文本控制器设置为 NULL 是有道理的,但如果你尝试正确,它应该会产生一些错误?
  • 不,实际上。 usernameController.text = appState.username ?? ''; 这张。代码实际上进行了一次空检查,并在值为 时分配空字符串。 null
  • 知道了,是的,这也可以解决问题(允许您将状态设置为 NULL,但仍然有 UI 反映空白字符串)。很好的额外奖励解决方案!
【解决方案2】:

正如其他 cmets 所描述的:

ChangeNotifier 属性设置为null 并调用NotifyListeners()(例如TextEditingController 文本值)不会更新检查null 的语句

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 2020-10-03
    • 2022-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多