在无状态小部件中使用TextFormField非常困难

时间:2018-08-23 07:07:01

标签: android ios flutter flutter-layout

我正在尝试在无状态小部件中使用TextFormField以及ScopedModel来处理其中的文本,并面临以下各种问题。

  1. 我尝试将控制器用于字段,但是每次我输入一些文本并在键盘上按完成时,都会清除文本。不知道为什么。

  2. 如果我删除控制器,文本将保留在字段中,但是会出现新的问题,即如何从字段中获取文本。我使用回调 onFieldSubmitted 解决了它。

  3. 但是事实证明,只有在我们单击键盘上的完成按钮时,才会调用 onFieldSubmitted 。如果我在字段中输入文本,而不是单击“确定”,则单击另一个字段,则不会调用回调,并且我也无法跟踪用户在字段中输入的内容。

有什么解决办法吗?

附加示例代码。

  class LoginPageStateless extends StatelessWidget {

  final loginUsernameController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomPadding: true,
      body: ScopedModelDescendant<AccountModel>(
        builder: (context, child, model) {
          return Form(
            //key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                TextFormField(
                  style: TextStyle(fontSize: 15.0),
                  decoration: InputDecoration(
                    labelText: 'Email id',
                    hintText: 'johndoe@ipropal.com',
                  ),
                  controller: loginUsernameController,
                  onFieldSubmitted: model.updateLoginUsernameText,
                ),
                TextFormField(
                  style: TextStyle(fontSize: 15.0),
                  decoration: InputDecoration(
                    labelText: 'Password',
                  ),
                  controller: loginUsernameController,
                  onFieldSubmitted: model.updateLoginUsernameText,
                  obscureText: true,
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}

3 个答案:

答案 0 :(得分:7)

您不能也不应使用Stateless小部件来存储长期变量。

问题是,这正是您要尝试的。 TextEditingController是应该在渲染之间保留的类实例。但是通过将其存储到StatelessWidget中,您基本上可以在每次更新后重新创建它。

您应该将窗口小部件转换为Stateful。并将该控制器移至State部分

答案 1 :(得分:2)

到目前为止,我还没有使用过TextFormField,因为它的简单性和灵活性,我一直使用TextField()。使用Redux和无状态窗口小部件时遇到了类似的问题,因为我在顶层存储中只有一个真实来源。因此,我必须在ViewModel中创建一些回调,然后将该回调分配给带有字符串参数的文本字段回调'onChanged'。

public class Dispenser extends Thread {

     List<Player> players = GameManager.getInstance().getRegisteredPlayers();

    public void run() {

       while (true) {
           System.out.println("alive");
           try {
               for (Player p : players) {
                   p.setAlk(p.getAlk() + p.getDifficulty()); // TODO too hard
               }
            } catch (ConcurrentModificationException e) {
                System.out.println("playerlist in use, retry");
            }
            try {
               sleep(1000); // TODO too short
            } catch (InterruptedException e1) {
               // TODO Auto-generated catch block
               e1.printStackTrace();
           }
        }
   }

}

在包裹在小部件中的TextField中(不提供更多详细信息)

CustomTextWidgetWrapper(
    onChangedCallback: viewModel.onChanged
),

然后在视图模型中,我获取字符串并将其分派到中央存储,以便在其他小部件中重用,例如获取数据并发送到服务器的按钮

new TextField(
    controller: myController, // no use practically now
    onChanged: onChangedCallback,

答案 2 :(得分:0)

您不能使用无状态小部件来存储长期变量。

让我们假设您有一个基本行为,例如当用户点击键盘将关闭的任何位置时,在无状态小部件中这是不可能的,因为每次打开或关闭键盘时,它都会重建并创建文本控制器的新实例,

因此在这种情况下,必须使用有状态小部件并将控制器放在状态类中