Flutter动态表单功能异常,求简易实现方案
Flutter 动态可添加项表单实现示例
核心实现思路
用列表存储每组表单的数据源,通过setState更新列表长度来动态添加/移除表单项,每组表单对应一个数据模型,绑定输入控件的值。
完整代码示例
import 'package:flutter/material.dart'; // 定义表单项的数据模型 class FormItem { String phone; String email; String selectedOption; FormItem({ this.phone = '', this.email = '', this.selectedOption = '', }); } class DynamicFormPage extends StatefulWidget { const DynamicFormPage({super.key}); @override State<DynamicFormPage> createState() => _DynamicFormPageState(); } class _DynamicFormPageState extends State<DynamicFormPage> { // 存储所有表单项的列表,初始化时默认添加一组 final List<FormItem> _formItems = [FormItem()]; // 表单全局key,用于验证和提交 final _formKey = GlobalKey<FormState>(); // 添加新的表单项 void _addFormItem() { setState(() { _formItems.add(FormItem()); }); } // 移除指定索引的表单项(至少保留一组) void _removeFormItem(int index) { if (_formItems.length > 1) { setState(() { _formItems.removeAt(index); }); } } // 提交表单,处理数据 void _submitForm() { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); // 这里可以处理收集到的表单数据,比如打印或上传 for (var item in _formItems) { print('手机号: ${item.phone}, 邮箱: ${item.email}, 选项: ${item.selectedOption}'); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('动态表单')), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( children: [ // 遍历生成所有表单项 ..._formItems.asMap().entries.map((entry) { int index = entry.key; FormItem item = entry.value; return Card( margin: const EdgeInsets.only(bottom: 16), child: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ // 手机号输入框 TextFormField( initialValue: item.phone, keyboardType: TextInputType.phone, decoration: const InputDecoration(labelText: '手机号'), validator: (value) { if (value == null || value.isEmpty) { return '请输入手机号'; } // 可添加手机号格式验证 return null; }, onSaved: (value) { item.phone = value!; }, ), const SizedBox(height: 12), // 邮箱输入框 TextFormField( initialValue: item.email, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(labelText: '邮箱'), validator: (value) { if (value == null || value.isEmpty) { return '请输入邮箱'; } // 可添加邮箱格式验证 if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return '请输入正确的邮箱格式'; } return null; }, onSaved: (value) { item.email = value!; }, ), const SizedBox(height: 12), // 下拉选择框 DropdownButtonFormField<String>( value: item.selectedOption.isNotEmpty ? item.selectedOption : null, decoration: const InputDecoration(labelText: '选择选项'), items: const [ DropdownMenuItem(value: 'option1', child: Text('选项1')), DropdownMenuItem(value: 'option2', child: Text('选项2')), DropdownMenuItem(value: 'option3', child: Text('选项3')), ], validator: (value) { if (value == null) { return '请选择一个选项'; } return null; }, onChanged: (value) { setState(() { item.selectedOption = value!; }); }, onSaved: (value) { item.selectedOption = value!; }, ), const SizedBox(height: 12), // 移除按钮(仅当存在多组时显示) if (_formItems.length > 1) ElevatedButton( onPressed: () => _removeFormItem(index), style: ElevatedButton.styleFrom(backgroundColor: Colors.redAccent), child: const Text('移除该项'), ), ], ), ), ); }).toList(), // 添加新项按钮 ElevatedButton( onPressed: _addFormItem, child: const Text('添加新的表单项'), ), const SizedBox(height: 20), // 提交按钮 ElevatedButton( onPressed: _submitForm, style: ElevatedButton.styleFrom(backgroundColor: Colors.green), child: const Text('提交表单'), ), ], ), ), ), ); } } // 可以在main函数中直接运行测试 void main() { runApp(const MaterialApp(home: DynamicFormPage())); }
关键细节说明
- 数据模型
FormItem:统一管理每组表单的手机号、邮箱和选中选项,确保每组数据独立不干扰。 - 动态列表管理:通过
_formItems列表的增删操作,结合setState触发UI更新,实现表单项的动态添加/移除。 - 表单验证与保存:使用
Form组件和全局_formKey统一管理表单验证,每个输入控件通过validator做校验,onSaved保存输入值到对应FormItem。 - 交互逻辑:移除按钮仅在表单项数量大于1时显示,避免清空所有表单;添加按钮点击后直接追加新的
FormItem到列表。
内容的提问来源于stack exchange,提问作者Mohammed Bekele
相关产品推荐
相关产品推荐

