跳到主内容

构建带验证的表单

如何构建一个能验证输入的表单。

应用经常需要用户在文本框中输入信息。例如,你可能需要用户通过电子邮件地址和密码组合来登录。

为了使应用安全且易于使用,请检查用户提供的信息是否有效。如果用户正确填写了表单,则处理相关信息。如果用户提交了错误信息,则显示友好的错误提示,告知他们哪里出了问题。

在这个示例中,通过以下步骤学习如何为包含单个文本框的表单添加验证:

  1. 创建一个包含 GlobalKeyForm
  2. 添加一个带有验证逻辑的 TextFormField
  3. 创建一个按钮来验证并提交表单。

1. 创建一个包含 GlobalKeyForm

#

创建一个 FormForm 组件充当容器,用于对多个表单字段进行分组和验证。

创建表单时,提供一个 GlobalKey。这会为你的 Form 分配一个唯一标识符。它还允许你在后续步骤中对表单进行验证。

将表单创建为 StatefulWidget。这样你就可以一次性创建唯一的 GlobalKey<FormState>()。然后,你可以将其存储为变量,并在不同位置访问它。

如果你将其设为 StatelessWidget,则需要将此键存储在*某处*。由于这非常消耗资源,因此你不会希望在每次运行 build 方法时都生成一个新的 GlobalKey

dart
import 'package:flutter/material.dart';

// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

// Define a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
  // Create a global key that uniquely identifies the Form widget
  // and allows validation of the form.
  //
  // Note: This is a `GlobalKey<FormState>`,
  // not a GlobalKey<MyCustomFormState>.
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    // Build a Form widget using the _formKey created above.
    return Form(
      key: _formKey,
      child: const Column(
        children: <Widget>[
          // Add TextFormFields and ElevatedButton here.
        ],
      ),
    );
  }
}

2. 添加一个带有验证逻辑的 TextFormField

#

尽管 Form 已经就位,但它还没有让用户输入文本的方式。这是 TextFormField 的工作。TextFormField 组件会渲染一个 Material Design 风格的文本框,并在出现验证错误时显示提示。

通过为 TextFormField 提供 validator() 函数来验证输入。如果用户的输入无效,validator 函数应返回一个包含错误消息的 String。如果没有错误,验证器必须返回 null。

在本例中,创建一个 validator 以确保 TextFormField 不为空。如果为空,则返回一条友好的错误消息。

dart
TextFormField(
  // The validator receives the text that the user has entered.
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please enter some text';
    }
    return null;
  },
),

3. 创建一个用于验证并提交表单的按钮

#

现在你已经拥有了一个带有文本框的表单,接下来提供一个按钮,供用户点击以提交信息。

当用户尝试提交表单时,检查表单是否有效。如果有效,显示成功消息。如果无效(例如文本框为空),则显示错误消息。

dart
ElevatedButton(
  onPressed: () {
    // Validate returns true if the form is valid, or false otherwise.
    if (_formKey.currentState!.validate()) {
      // If the form is valid, display a snackbar. In the real world,
      // you'd often call a server or save the information in a database.
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Processing Data')),
      );
    }
  },
  child: const Text('Submit'),
),

这是如何工作的?

#

要验证表单,请使用第 1 步中创建的 _formKey。你可以使用 _formKey.currentState 访问器来获取 FormState,它是 Flutter 在构建 Form 时自动创建的。

FormState 类包含 validate() 方法。当调用 validate() 方法时,它会为表单中的每个文本框运行 validator() 函数。如果一切正常,validate() 方法返回 true。如果任何文本框包含错误,validate() 方法会重新构建表单以显示错误消息,并返回 false

互动示例

#
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Form Validation Demo';

    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(title: const Text(appTitle)),
        body: const MyCustomForm(),
      ),
    );
  }
}

// Create a Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
  // Create a global key that uniquely identifies the Form widget
  // and allows validation of the form.
  //
  // Note: This is a GlobalKey<FormState>,
  // not a GlobalKey<MyCustomFormState>.
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    // Build a Form widget using the _formKey created above.
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          TextFormField(
            // The validator receives the text that the user has entered.
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter some text';
              }
              return null;
            },
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 16),
            child: ElevatedButton(
              onPressed: () {
                // Validate returns true if the form is valid, or false otherwise.
                if (_formKey.currentState!.validate()) {
                  // If the form is valid, display a snackbar. In the real world,
                  // you'd often call a server or save the information in a database.
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text('Processing Data')),
                  );
                }
              },
              child: const Text('Submit'),
            ),
          ),
        ],
      ),
    );
  }
}

要了解如何检索这些值,请查看获取文本框的值食谱。