【问题标题】:TextEditingController vs OnChangedTextEditingController 与 OnChanged
【发布时间】:2019-11-16 03:53:24
【问题描述】:

我正在寻找有关 TextEditingController 优于 OnChanged 事件对 TextField 的好处的更好解释。

我的理解是 onChanged 的​​ setState 通知所有小部件状态变量值的变化。这样,任何小部件(例如文本)都可以简单地使用状态变量,并且会在其更改时收到通知。

我的错误希望是 TextEditingController 会让我什至不需要状态变量变得更加简单。如下所示:

import "package:flutter/material.dart";

class TestForm extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TestFormState();
  }
}

class TestFormState extends State<TestForm> {
  //string myStateVariable = "";
  final ctrl = TextEditingController();

  @override
  Widget build(BuildContext context) {

    var tf = TextField(
      controller: ctrl,
    );

    var t = Text("Current value: " + ctrl.text);  // <<<<<<<<<<< false hope! doesnt work!

    var x = Column(children: <Widget>[tf,t],);

    return MaterialApp(home: Material(child: Scaffold(
      appBar: AppBar(title: Text("Test Form"),),
      body: x,
    )));
  }
}

谁能解释为什么 TextEditingController 或类似的东西不能管理状态本身并通知所有消费者状态变化?

谢谢。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    您只是没有同步设置状态而已。 onChanged 所做的事情完全可以通过这种方法实现:

    class _TestFormState extends State<TestForm> {
      late TextEditingController controller;
    
      @override
      void initState() {
        controller = TextEditingController()
          ..addListener(() {
            setState(() {});
          });
        super.initState();
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            Text('Current Value: ${controller.text}'),
            TextField(
              controller: controller,
            ),
          ],
        );
      }
    }
    

    如您所见,我们有监听器在每次控制器状态更改时设置状态。这正是onChanged 所做的。

    所以,关于收益,你可以通过这两种方法实现一切,这是一种主观的方式。

    关于福利: 如果您需要在Stream 中保存字段值,则需要onChanged。在其他情况下,您可以使用controller

    实际上,在我看来,大部分时间你都不需要两者,因为TextFormField + Form 中的StatefulWidget 是实现表单页面的非常完整的方式。结帐食谱:https://flutter.dev/docs/cookbook/forms/validation

    【讨论】:

    • @S2L 我也添加了我的想法,希望对您有所帮助。
    • 问题:如何处理变量绑定,例如假设在 TextField 的 setState 中更新了两个变量,并且这两个变量随后出现在两个不同的 Text 小部件中。那么变量更改如何传播到正确的文本小部件? (我假设每个 Text 小部件只获取它使用的变量的事件)。谁记录哪个小部件需要哪个变量更改事件?
    • 另外,有没有办法在没有这个控制器的情况下清除 TextField?我可以在网上找到的唯一方法是 controllerObject.Text = "" 或 clear 方法。有什么方法可以在不使用 Controller 的情况下做到这一点?
    • 我在使用TextEditingController 时遇到的一个问题是_formKey.currentState.reset() 不会重置具有自定义控制器的字段。
    • @AlanCabrera 你确定,你正确使用了密钥吗?我建议您打开新问题以获得答案。
    【解决方案2】:

    TextEditingController 实际上是在管理他自己的状态,这就是为什么一旦你改变它就可以在屏幕上看到输入。

    这里有 2 个问题,第一个是您没有向 TextEditingController 添加任何侦听器,您只是在构建小部件时才询问“给我当前值”,而不是“随时给我值”变化”。为此,您需要向文本控制器添加一个侦听器,并且每次值更改时都会调用它。

    试试这个:

      @override
      void initState() {
        super.initState();
        // Start listening to changes.
        ctrl.addListener(_printValue);
      }
    
      _printValue() {
        print("Value: ${ctrl.text}");
      }
    

    这将起作用,因为 print 不需要在屏幕上呈现任何内容,但如果您将其更改为返回一个小部件,它也将不起作用。这是第二个问题,正如您所指出的,当值更改时,您的父小部件没有被重建,在这种情况下,当值更改时,您无法避免 setState (或其他方式告诉颤振需要重建小部件),因为您需要重新构建小部件以查看更改。

    另一件不喜欢指出的事情是 TextEditingController 非常强大,它可以用于更多的事情,只需将通知添加到更改。例如,如果您想要屏幕其他部分的按钮清除 TextField 上的文本,则需要将 TextEditingController 绑定到该字段。

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 2020-10-31
      • 1970-01-01
      • 2021-08-03
      • 2012-05-07
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多