如何清除 Flutter 中 TextFormField 中的错误消息

And*_*sky 20 flutter

在我的代码中,我验证了电话号码。如果电话号码不正确 - 我会显示错误消息。但是,当用户开始编辑号码时,我想隐藏此错误消息。

我已经找到了解决方案currentState.reset(),但似乎不是很好的解决方案。我必须处理保存文本和光标位置的问题。而且我还有一件小神器。通常当我按住退格键时 - 它会一一删除符号。如果我在显示错误消息时执行此操作 - 则错误消息会消失并且只删除一个符号。

有人知道这种情况的正确解决方案吗?

final TextEditingController controller = TextEditingController();
final RegExp _phoneRegex = RegExp(r"^\+{1}\d{10, 15}\$");
bool isError = false;
TextSelection currentPosition;

return Column(
  children: <Widget>[
    Form(
        key: _textKey,
        child: TextFormField(
          controller: controller,
          validator: (str) {
            isError = true;
            if (str.isEmpty) {
              return err_empty_field;
            } else if (!_phoneRegex.hasMatch(str)) {
              return err_invalid_phone;
            }
            isError = false;
          },
        ),
        onChanged: () {
          if (controller.selection.start < 0 &&
              controller.text.length > 0) {
            TextSelection position =
                controller.text.length > currentPosition.start
                    ? currentPosition
                    : TextSelection.fromPosition(
                        TextPosition(offset: controller.text.length));
            controller.selection = position;
          }
          if (isError) {
            isError = false;
            currentPosition = controller.selection;
            if (currentPosition.start > controller.text.length) {
              currentPosition = TextSelection.fromPosition(
                  TextPosition(offset: controller.text.length));
            }
            String currentText = controller.text;
            _textKey.currentState.reset();
            controller.text = currentText;
            controller.selection = currentPosition;
          }
        },
      ),
    RaisedButton(
      onPressed: () {
        _textKey.currentState.validate();
      },
      child: Text(login),
    )
  ],
);
Run Code Online (Sandbox Code Playgroud)

coo*_*z71 25

这是解决此问题的合适方法。

您实际上不需要使用onChanged或任何导致副作用的提示,我通过创建一个初始化为的类属性来解决它false

bool _autovalidate = false;
Run Code Online (Sandbox Code Playgroud)

表单小部件有一个命名属性autovalidate。您应该将它传递给前一个布尔值:

Form(
  key: _textKey,
  autovalidate: _autovalidate,
  ... 
)
Run Code Online (Sandbox Code Playgroud)

在您的提交按钮onPressed()方法中,您应该将_autovalidate布尔值更新为true表单是否为invalid,这将使表单在每次onChanged调用时自动验证 TextFormField :

RaisedButton(
  onPressed: () {
    if (_textKey.currentState.validate()) {
      print('valid');
    } else {
      print('invalid');
      setState(() => _autoValidate = true);
    }
  },
  child: Text(login),
)
Run Code Online (Sandbox Code Playgroud)

我希望它帮助某人。

编辑(2020 年 11 月)

autovalidate在 v1.19.0 之后被弃用。
而是使用autovalidateMode

Form(
  autovalidateMode: AutovalidateMode.onUserInteraction`.
  ...
)
Run Code Online (Sandbox Code Playgroud)

  • 我建议仅在用户尝试使用 setState 提交表单一次后才使用 AutovalidateMode.onUserInteraction,否则,用户将开始输入并立即显示错误 - 这不是最好的用户体验。 (3认同)

coo*_*z71 11

2021 年 1 月

...

AutovalidateMode _autoValidate = AutovalidateMode.disabled;
Run Code Online (Sandbox Code Playgroud)
Form(
  key: _textKey,
  autovalidateMode: _autovalidate,
  ... 
)
Run Code Online (Sandbox Code Playgroud)
RaisedButton(
  onPressed: () {
    if (_textKey.currentState.validate()) {
      print('valid');
    } else {
      print('invalid');
      setState(() => _autoValidate = AutovalidateMode.always);
    }
  },
  child: Text("login"),
)
Run Code Online (Sandbox Code Playgroud)


Nis*_*ara 6

这里的问题是errorText自动管理validator领域TextFormField。同时,简单的解决方案是errorText 手动处理.

第 1 步:创建

  • 字符串字段,_errorText初始化为null. 该字段将保存需要显示的错误消息。
  • 布尔字段,_error初始化为false. true如果有错误,则归档false

第2步:

  • 分配_errorTextTextFormField

第 3 步(重要):

  • 确保TextFormField validator返回一个null值。

  • 在此处处理验证并将正确的错误消息分配给_errorText

  • _error相应地更新状态。

第 4 步(重要):

  • 重置_errorText_error。这将在您开始编辑时立即从字段中删除错误。

第 5 步:

  • 触发字段验证onFieldSubmitted并管理您的代码流...
import 'package:flutter/material.dart';

class WorkGround extends StatefulWidget {
  @override
  _WorkGroundState createState() => _WorkGroundState();
}

class _WorkGroundState extends State<WorkGround> {
  final _formKey = GlobalKey<FormState>();
  final _usernameFocusNode = FocusNode();
  final _phoneNumberFocusNode = FocusNode();

  /*
  * Step 1.
  * */
  String _userNameErrorText;
  bool _userNameError = false;
  String _phoneNumberErrorText;
  bool _phoneNumberError = false;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            TextFormField(
              focusNode: _usernameFocusNode,
              decoration: InputDecoration(
                labelText: 'Username',
                /*
                * Step 2
                * */
                errorText: _userNameErrorText, // Handling error manually
              ),
              textInputAction: TextInputAction.next,
              /*
              * Step 3
              * */
              validator: (value) {
                setState(() {
                  if(value.isEmpty) {
                    _userNameError = true;
                    _userNameErrorText = 'Enter Username';
                  }
                });
                return null; // Return null to handle error manually.
              },
              /*
              * Step 4
              * */
              onChanged: (value) {
                setState(() {
                  _userNameError = false;
                  _userNameErrorText = null; // Resets the error
                });
              },
              /*
              * Step 5
              * */
              onFieldSubmitted: (value) {
                _formKey.currentState.validate(); // Trigger validation
                if(!_userNameError) {
                  FocusScope.of(context).requestFocus(_phoneNumberFocusNode);
                }
              },
            ),
            TextFormField(
              focusNode: _phoneNumberFocusNode,
              decoration: InputDecoration(
                labelText: 'Phone Number',
                /*
                * Step 2
                * */
                errorText: _phoneNumberErrorText, // Handling error manually
              ),
              textInputAction: TextInputAction.done,
              /*
              * Step 3
              * */
              validator: (value) {
                setState(() {
                  if(value.isEmpty) {
                    _phoneNumberError = true;
                    _phoneNumberErrorText = 'Enter Phone number';
                  } else if( value.length < 10) {
                    _phoneNumberError = true;
                    _phoneNumberErrorText = 'Invalid Phone number';
                  }
                });
                return null; // Return null to handle error manually.
              },
              /*
              * Step 4
              * */
              onChanged: (value) {
                setState(() {
                  _phoneNumberError = false;
                  _phoneNumberErrorText = null; // Resets the error
                });
              },
              /*
              * Step 5
              * */
              onFieldSubmitted: (value) {
                _formKey.currentState.validate(); // Trigger validation
                if(!_phoneNumberError) {
                  // submit form or whatever your code flow is...
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

Run Code Online (Sandbox Code Playgroud)


And*_*sky 3

我找到了工作且更简单的方法

final _textKey = GlobalKey<FormState>();
final TextEditingController _controller = TextEditingController();

Widget _getPhoneInputForm() {
  final RegExp _phoneRegex = RegExp(r"^\+{1}\d{10,17}");
  bool isError = false;
  bool isButtonPressed = false;

  return Column(
    crossAxisAlignment: CrossAxisAlignment.center,
    mainAxisSize: MainAxisSize.max,
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Padding(
        padding: EdgeInsets.symmetric(horizontal: 36.0),
        child: Form(
          key: _textKey,
          child: TextFormField(
            keyboardType: TextInputType.phone,
            decoration: InputDecoration(
                hintText: hint_enter_phone,
                contentPadding: EdgeInsets.all(24.0),
                fillColor: Colors.blueGrey.withOpacity(0.3),
                filled: true,
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(16.0)),
                    borderSide: BorderSide(color: Colors.blueGrey))),
            controller: _controller,
            validator: (str) {
              if (!isButtonPressed) {
                return null;
              }
              isError = true;
              if (str.isEmpty) {
                return err_empty_field;
              } else if (!_phoneRegex.hasMatch(str)) {
                return err_invalid_phone;
              }
              isError = false;
            },
            onFieldSubmitted: (str) {
              if (_textKey.currentState.validate()) _phoneLogin();
            },
          ),
          onChanged: () {
            isButtonPressed = false;
            if (isError) {
              _textKey.currentState.validate();
            }
          },
        ),
      ),
      RaisedButton(
        color: Colors.teal,
        textColor: Colors.white,
        onPressed: () {
          isButtonPressed = true;
          if (_textKey.currentState.validate()) _phoneLogin();
        },
        child: Text(login),
      )
    ],
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 在巴西,这被称为“GAMBIARR A”。 (9认同)