Flutter Enable/Disable 基于TextFormField内容的按钮

Flutter Enable/Disable Button based on TextFormField content

如何 activate/deactivate 基于 TextFormField 内容的按钮?

我想确保用户只有在 TextFormField 中输入了 10 个数字(如果是手机号码)时才能按下按钮 X。

谢谢!

一个简单的方法是将我们的 TextFormField 的自动验证 属性 设置为 true。这将自动检测我们的 TextFormField 小部件上的更改。然后我们可以尝试在验证器 属性 上检查我们的 TextFormField 的值是否具有 10 个字符的字符串长度。之后我们可以调用 setState 来启用或禁用我们的按钮(我在这个例子中使用 FlatButton)。

bool _btnEnabled = false;

...

@override
Widget build(BuildContext context){

  ...

  TextFormField(

    ...
    autovalidate: true,
    validator: (String txt){
      if (txt.length == 10){
        setState((){
          _btnEnabled = true;
        });
      } else {
        setState((){
          _btnEnabled = false;
        });
      }
    }

    ...

  FlatButton(
    onPressed: _btnEnabled == true ? yourCallback : null,
    child: ...

接受的答案似乎无法使用最新的 Flutter v1.7.8(稳定),它给我以下错误:

无法将此 TestForm 小部件标记为需要构建,因为框架已经在构建小部件的过程中

工作版本如下所示:

...
autovalidate: true,
validator: (String txt){
      bool isValid = txt.length == 10;
      if (isValid != _btnEnabled) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          setState(() {
            _btnEnabled = txt.length == 10;
          });
        });
      } 
}

...

小部件的状态可以在表单的 onChanged 回调中更新,只要任何表单字段的值发生变化,回调就会被调用。在那里您可以使用表单键来验证表单并将标志设置为 enable/disable 按钮。此解决方案允许您缩放以禁用具有多个字段的表单中的按钮。例如,

/// Key used to reference the form.
final _formKey = GlobalKey<FormState>();

...

Form(
  key: _formKey,
  onChanged: () => setState(() => _enableBtn = _formKey.currentState.validate()),
  child: ListView(
    children: <Widget>[
      TextFormField(
        validator: (value) => value.length < 10 ?
          'Number must be at least 10 digits' : // return an error message
          null,
        ...
      ),
    ],
  ),
)

...

FlatButton(
  onPressed: _enableBtn ?
    () => _doSomething() :
    null, // setting onPressed to null disables the button.
  ...

出现错误 "setState() or markNeedsBuild() called during build.",答案已被接受。只需添加 Future.delayed(Duration.zero).then(....) 作为技巧解决方案,它在 flutter 1.12.13

上运行
TextFormField(

...
autovalidate: true,
validator: (String txt){
  if (txt.length == 10){
    Future.delayed(Duration.zero).then((_){
    setState((){
      _btnEnabled = true;
    });
  });
  } else {
    Future.delayed(Duration.zero).then((_){
    setState((){
      _btnEnabled = false;
    });
  });
  }
}
....

你可以使用 Flutter Reactive Forms。这是一种处理表单输入和验证的模型驱动方法,深受 Angular 的 Reactive Forms 的启发。

使用 libray 非常简单,在文档中有一个部分解释了如何 Enable/Disable 根据整个表单的有效性提交按钮,而不仅仅是一个字段。

你可以使用这个方法。

  bool isEnable = false;

void validateButton() {
    bool isValid = true;

    isValid = userEmail.isNotEmpty &&
        userPassword.isNotEmpty &&
        validateEmail(userEmail) &&
        userPassword.length >= 8;

    setState(() {
      isEnable = isValid;
    });
  }

现在在您的文本字段 onChanged 方法中,您必须调用此函数

像这样

onChanged: (email) {
                        userEmail = email;
                        setState(() {});
                        validateButton();
                      },

并在您的登录按钮中

isEnable?ActiveButton():DisableButton()