應用通常要求使用者在文字欄位中輸入資訊。例如,你可能要求使用者使用電子郵件地址和密碼組合登入。

為了使應用安全且易於使用,請檢查使用者提供的資訊是否有效。如果使用者正確填寫了表單,則處理資訊。如果使用者提交了不正確的資訊,則顯示友好的錯誤訊息,告知他們出了什麼問題。

在此示例中,你將學習如何透過以下步驟向包含單個文字欄位的表單新增驗證:

  1. 使用 GlobalKey 建立一個 Form
  2. 新增一個帶有驗證邏輯的 TextFormField
  3. 建立一個按鈕以驗證並提交表單。

1. 使用 GlobalKey 建立一個 Form

#

建立一個 FormForm widget 作為容器,用於分組和驗證多個表單欄位。

建立表單時,提供一個 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 widget 呈現一個 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'),
            ),
          ),
        ],
      ),
    );
  }
}

要了解如何檢索這些值,請檢視檢索文字欄位的值菜譜。