我是 Flutter(和 Dart)的新手,在尝试构建表单来编辑对象时,我在网上搜索了示例和教程,我看到这两种方法都被使用了。
两者有什么区别?我应该使用哪一个?
如果您
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回调。
如果您不知道自己需要什么,请使用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
}
},
),
],
),
);
}
}
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.
TextFormField对比TextFieldTextFormField返回 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并使用自定义代码分别验证每个内容要方便得多。
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 年 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),
),
],
);
},
),
经验法则:如果您的盒子只有一个输入字段,只需使用原材料输入TextField(FormField尽管在这种情况下有点矫枉过正)。如果您的框有许多输入字段,您需要将每个输入字段包装在一个FormField中,然后将它们全部集成到Form小部件中,以便获得一次验证和保存所有表单字段的好处。
额外提示:如果你有一个TextField包裹在 aFormField中,它不允许用户输入任何文本,例如 aCupertinoPickerFormField或 a SimpleDialogFormField,它为用户提供多个选项之间的选择(基本上是一个SimpleDialog包裹在 a 中的材料小部件FormField),只需简单地使用不 用于操作文本的hintText参数。使用 . 使提示文本具有与正常输入文本相同的颜色。InputDecorationTextEditingControllerhintStyle: const TextStyle(color: Color(0xdd000000))
这个来自 Flutter Europe 的视频将帮助您立即掌握 Flutter 中的表单。