TextFormField 和 TextField 的区别是什么?

我对 Flutter (和 Dart)还是个新手,当我试图构建一个表单来编辑一个对象时,我在网上搜索了一些例子和教程,我看到这两个都用到了。

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

69299 次浏览

TextField是一个简单的文本字段 TextFormField是要在表单中使用的文本字段(您需要关心用户输入)。

如果不需要验证 TextField。 如果需要验证用户输入,请在 validator中使用 TextFormField。

如果您在需要保存、重置或验证的地方制作 Form operations- use TextFormField. Else For Simple user input capture TextField就够了。

TextFormField, which integrates with the Form widget.

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

不需要 Form祖先。表单只是使 同时保存、重置或验证多个字段更容易。

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

sample:

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;
},
)

TextField,这是没有与 Form集成的底层文本字段。

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

长话短说

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

文本字段

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

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

enter image description here

要获得用户输入的文本,您可以在每次发生这样的更改时获得通知:

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

或者你可以使用 TextEditingController,如描述的 给你。这将给你访问文本状态。

TextFormField

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

enter image description here

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

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

下面是 文件的一个精简例子:

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
}
},
),
],
),
);
}
}

参见

TextFormFieldTextField

TextFormField返回一个 TextField,但是用额外的功能包装了 TextField,这些功能可以通过 Form使用,也可以不使用(例如重置、验证、保存等)。

一般情况下,您希望使用 TextFormField,除非您喜欢编写常规代码。

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

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

After registration, these FormField widgets can be changed by that parent Form.

Form is also a StatefulWidget. It has a FormState object. FormState可以获取和设置注册到它的任何/allFormFields上的数据。

For example to clear the entire form we can call reset() on FormState and FormState will iterate through all child FormFields registered, resetting each FormField to its initialValue (null by default).

验证是在 Form/FormState中放置几个类似于 TextFormFieldFormField的另一个常见用例。这允许在 Form上通过单个 validate()调用验证多个字段。

怎么做到的?FormState有一个 validate()方法,该方法迭代每个已注册的 FormField并调用该 FormField's validate()方法。在 Form上调用一次 validate()要比手动跟踪所有 TextField并用自定义代码分别验证每个 TextField方便得多。

细节

TextFormField 如何向 Form 注册自身?

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

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

The ? is in case there is no Form widget parent. The _register call will only be run 如果 there a Form & FormState somewhere above.

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

When a parent widget is an InheritedWidget, any child can find that parent using a special “给我找一个这种类型的父母” method.

Here's how that "find me" method is used/exposed inside Form as a static method we can call from anywhere:

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

方法 dependOnInheritedWidgetOfExactType的命名有点复杂。它作为 findInheritedWidgetOfExactType更具可读性,但它不仅仅是查找。(我们可以通过已经注册为 dependOn这个 FormState的孩子来触发 Form的重建)。

Summary

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

我认为这可能是对两者之间差异的最简明扼要的解释。

来自 资料库:

材料设计文本字段。

TextFormField: 包含 TextFieldFormField

Similarly, you can wrap FormField around any cupertino input component such as CupertinoTextField

下面是一个关于自定义 CheckboxFormField的例子,它是一个包裹材料设计组件 CheckboxFormField:

// 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),
),
],
);
},
),

经验法则 : 如果您的机器只有一个输入字段,那么只需使用原材料输入,如 TextField(但是在这种情况下 FormField有点过分)。如果您的机器有许多输入字段,那么您需要将它们中的每一个封装在一个 FormField中,然后将所有这些字段集成到 Form小部件中,从而获得一次性验证和保存所有表单字段的好处。

额外提示 : 如果你有一个 TextField封装在一个 FormField,不允许用户输入任何文本,如 CupertinoPickerFormFieldSimpleDialogFormField,提供给用户几个选项之间的选择(这基本上是一个材料 SimpleDialog小部件包装在一个 FormField) ,只是简单地使用 InputDecorationhintText参数,而不使用 TextEditingController操纵文本。使提示文本具有与 hintStyle: const TextStyle(color: Color(0xdd000000))的正常输入文本相同的颜色。

This 来自 Flutter Europe 的视频 will help you master forms in Flutter in no time.