103

我是 Flutter(和 Dart)的新手,在尝试构建表单来编辑对象时,我在网上搜索了示例和教程,我看到这两种方法都被使用了。

两者有什么区别?我应该使用哪一个?

4

5 回答 5

90

如果您Form在需要保存、重置或验证操作的地方进行操作,请使用TextFormField. Else 对于简单的用户输入捕获 TextField就足够了。

TextFormField,它与Form小部件集成。

这是一个将 TextField 小部件包装在 FormField 中的便利小部件。

不需要Form祖先。表单只是让一次保存、重置或验证多个字段变得更加容易。

要在没有表单的情况下使用,请将 GlobalKey 传递给构造函数并使用 GlobalKey.currentState 保存或重置表单字段。

样本:

TextFormField(
  autovalidateMode: AutovalidateMode.always
  decoration: const InputDecoration(
    icon: Icon(Icons.person),
    hintText: 'What do people call you?',
    labelText: 'Name *',
  ),
  onSaved: (String value) {
    // This optional block of code can be used to run
    // code when the user saves the form.
  },
  validator: (String value) {
    return value.contains('@') ? 'Do not use the @ char.' : null;
  },
)

TextFieldForm,这是没有集成的基础文本字段。

onChanged每当用户更改字段中的文本时,文本字段都会调用回调。如果用户指示他们已完成在字段中的输入(例如,通过按下软键盘上的按钮),则文本字段调用onSubmitted回调。

于 2019-02-13T07:13:45.500 回答
29

简短的回答

如果您不知道自己需要什么,请使用TextField. 这是从用户获取文本输入的最基本的 Flutter 小部件。这是你应该首先掌握的。

文本域

使用 aTextField是一种允许用户输入的简单方法。

TextField(
  decoration: InputDecoration(
    hintText: 'Name'
  ),
);

在此处输入图像描述

要获取用户输入的文本,您可以在每次发生更改时收到通知,如下所示:

TextField(
  decoration: InputDecoration(
      hintText: 'Name'
  ),
  onChanged: (text) {
    // do something with text
  },
),

或者您可以使用 a TextEditingController,如此所述。这将使您可以访问文本状态。

文本表单域

如果您发现自己需要在保存之前验证用户文本输入,您可以考虑使用TextFormField. 想象一下这样的事情:

在此处输入图像描述

您可能希望对用户名和密码进行许多验证检查。

当然,您仍然可以只使用几个 TextField,但TextFormField具有额外的内置功能,可以让您的生活更轻松。通常,只有在小部件TextFormField内部使用 a 时才会使用它Form(尽管这不是严格要求)。

这是文档中的一个精简示例:

class MyCustomForm extends StatefulWidget {
  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

class MyCustomFormState extends State<MyCustomForm> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
          TextFormField(
            validator: (value) {
              // validation logic
            },
          ),
          RaisedButton(
            child: Text('Submit'),
            onPressed: () {
              if (_formKey.currentState.validate()) {
                // text in form is valid
              }
            },
          ),
        ],
      ),
    );
  }
}

也可以看看

于 2020-03-27T05:02:07.620 回答
15

TextField is a simple text field. (you don't care about user input) TextFormField is a text field to be used in a form (you care about user input).

If you don't need to validate TextField. If you need to validate user input, use TextFormField with validator.

于 2019-02-13T02:47:15.017 回答
6

TextFormField对比TextField

TextFormField返回 a TextField,但包含TextField额外的功能,您可以通过 a 使用Form,也可以不使用(例如重置、验证、保存等)。

TextFormField通常,除非编写样板代码是您的事,否则您想使用它。

如何TextFormField工作?它能做什么?

TextFormField扩展FormField类,(a StatefulWidget)。 FormField对象在实例化时会做一件特殊的事情:它们在小部件树中查找 aForm并将自己注册到 that Form

注册后,这些FormField小部件可以由该 parent 更改Form

Form也是一个StatefulWidget。它有一个FormState对象。 FormState可以获取和设置任何/所有FormFields注册到它的数据。

例如,要清除整个表单,我们可以调用reset()并遍历所有注册的子项FormState,将每个子项重置为其(默认为 null)。FormStateFormFieldsFormFieldinitialValue

验证是另一种常见的用例,用于在 /中放置多个FormField类似。这允许通过对.TextFormFieldFormFormStatevalidate()Form

如何? FormState有一个validate()方法遍历每个注册FormField并调用该FormField's validate()方法。validate()一次调用Form比您手动跟踪所有内容TextField并使用自定义代码分别验证每个内容要方便得多。

细节

TextFormField 如何在表单中注册自己?

FormField(基类TextFormField等)在他们的build()方法中进行调用: Form.of(context)?._register(this);

在英语中,这意味着: 搜索我的上下文层次结构,直到我们找到一个Form小部件(如果有)并使用该表单注册自己。

?是在没有Form小部件父级的情况下。只有在上面有&_register才会运行调用。FormFormState

如何Form.of(context)?._register(this)工作?

Form&FormState偷偷使用InheritedWidget。在FormState.build() 中,您将看到以下代码:

return WillPopScope(
      onWillPop: widget.onWillPop,
      child: _FormScope( // ← sneaky
        formState: this,
        generation: _generation,
        child: widget.child,
      ),
    );

看着_FormScope我们看到:

class _FormScope extends InheritedWidget

当父窗口小部件是 时InheritedWidget,任何孩子都可以使用特殊的“为我找​​到这个确切类型的父母”方法找到该父母。

这是“找到我”方法在内部Form作为静态方法使用/公开的方式,我们可以从任何地方调用:

static FormState of(BuildContext context) {
    final _FormScope scope = context.dependOnInheritedWidgetOfExactType<_FormScope>();
    return scope?._formState;
  }

该方法的命名dependOnInheritedWidgetOfExactType有点棘手。它会更具可读性findInheritedWidgetOfExactType,但它不仅仅是查找。Form(我们可以通过注册为dependOnthis的子节点触发重建FormState)。

概括

TextFormField是豪华套装、空调、蓝牙连接的 8 扬声器立体声版本TextField。它包含许多在接受用户输入信息时会用到的常用功能。

于 2021-03-25T01:35:04.947 回答
3

2021 年 10 月)我认为这可能是对两者之间差异的最简洁和简单的解释。

材料库

TextField:材料设计文本字段。

TextFormField: 一个FormField包含一个TextField.

同样,您可以环绕FormField任何 Cupertino 输入组件,例如CupertinoTextField

下面是一个关于 custom 的示例CheckboxFormField,它是一个FormField围绕材料设计组件的Checkbox

// A custom CheckboxFormField, which is similar to the built-in TextFormField
bool agreedToTerms = false;
FormField(
  initialValue: false,
  validator: (value) {
    if (value == false) {
      return 'You must agree to the terms of service.';
    }
    return null;
  },
  builder: (FormFieldState formFieldState) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Checkbox(
              value: agreedToTerms,
              onChanged: (value) {
                // When the value of the checkbox changes,
                // update the FormFieldState so the form is
                // re-validated.
                formFieldState.didChange(value);
                setState(() {
                  agreedToTerms = value;
                });
              },
            ),
            Text(
              'I agree to the terms of service.',
              style: Theme.of(context).textTheme.subtitle1,
            ),
          ],
        ),
        if (!formFieldState.isValid)
          Text(
            formFieldState.errorText ?? "",
            style: Theme.of(context)
                .textTheme
                .caption
                .copyWith(color: Theme.of(context).errorColor),
          ),
      ],
    );
  },
),

经验法则:如果您的盒子只有一个输入字段,只需使用原材料输入TextFieldFormField尽管在这种情况下有点矫枉过正)。如果您的框有许多输入字段,您需要将每个输入字段包装在一个FormField中,然后将它们全部集成到Form小部件中,以便获得一次验证和保存所有表单字段的好处。

额外提示:如果你有一个TextField包裹在 aFormField中,它不允许用户输入任何文本,例如 aCupertinoPickerFormField或 a SimpleDialogFormField,它为用户提供多个选项之间的选择(基本上是一个SimpleDialog包裹在 a 中的材料小部件FormField),只需简单地使用不 用于操作文本的hintText参数。使用 . 使提示文本具有与正常输入文本相同的颜色。InputDecorationTextEditingControllerhintStyle: const TextStyle(color: Color(0xdd000000))

这个来自 Flutter Europe 的视频将帮助您立即掌握 Flutter 中的表单。

于 2021-05-20T15:32:12.283 回答