Skip to content

表单 Form

Form 配合 TextFormField 实现表单验证和提交。

基本结构

dart
class _MyFormPageState extends State<MyFormPage> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          // 表单字段...
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate()) {
                // 验证通过
                _formKey.currentState!.save();
                _submit();
              }
            },
            child: const Text('提交'),
          ),
        ],
      ),
    );
  }
}

TextFormField

dart
TextFormField(
  controller: _nameController,
  decoration: const InputDecoration(
    labelText: '用户名',
    prefixIcon: Icon(Icons.person),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) return '请输入用户名';
    if (value.length < 3) return '用户名至少 3 个字符';
    return null;  // null 表示验证通过
  },
  onSaved: (value) {
    // 保存值
    _formData['name'] = value;
  },
)

完整示例

dart
class RegisterForm extends StatefulWidget {
  // ...
}

class _RegisterFormState extends State<RegisterForm> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _submit() {
    if (_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      // 发送数据
      print('name: ${_nameController.text}');
      print('email: ${_emailController.text}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            // 用户名
            TextFormField(
              controller: _nameController,
              decoration: const InputDecoration(
                labelText: '用户名',
                prefixIcon: Icon(Icons.person),
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) return '请输入用户名';
                return null;
              },
            ),
            const SizedBox(height: 16),

            // 邮箱
            TextFormField(
              controller: _emailController,
              keyboardType: TextInputType.emailAddress,
              decoration: const InputDecoration(
                labelText: '邮箱',
                prefixIcon: Icon(Icons.email),
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) return '请输入邮箱';
                if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
                  return '邮箱格式不正确';
                }
                return null;
              },
            ),
            const SizedBox(height: 16),

            // 密码
            TextFormField(
              controller: _passwordController,
              obscureText: true,
              decoration: const InputDecoration(
                labelText: '密码',
                prefixIcon: Icon(Icons.lock),
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.length < 6) return '密码至少 6 位';
                return null;
              },
            ),
            const SizedBox(height: 24),

            // 提交按钮
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _submit,
                child: const Text('注册'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Form 常用方法

dart
_formKey.currentState!.validate()   // 验证所有字段,返回 bool
_formKey.currentState!.save()       // 触发所有字段的 onSaved
_formKey.currentState!.reset()      // 重置所有字段

FormField — 自定义表单字段

dart
FormField<String>(
  validator: (value) {
    if (value == null || value.isEmpty) return '请选择';
    return null;
  },
  builder: (FormFieldState<String> state) {
    return DropdownButtonFormField<String>(
      initialValue: state.value,  // Flutter 3.35+ 使用 initialValue 替代 value
      items: ['选项A', '选项B', '选项C'].map((e) =>
        DropdownMenuItem(value: e, child: Text(e))
      ).toList(),
      onChanged: (value) {
        state.didChange(value);
      },
      decoration: InputDecoration(
        labelText: '选择项',
        errorText: state.errorText,
      ),
    );
  },
)

::: info Flutter 3.35 变更
`DropdownButtonFormField` 的 `value` 参数在 Flutter 3.35 中已废弃,改用 `initialValue`。旧名称 `value` 容易与受控组件混淆,新名称更准确地表达了其语义(仅用于初始值)。
:::

基于 Flutter 官方文档整理