Flutter中如何按对象内嵌数组格式POST提交动态表单响应
Flutter动态表单提交适配后端格式解决方案
1. 定义匹配后端格式的数据模型类
先明确对应的数据结构,避免手动拼接JSON出错:
// 单个表单响应项,对应activity_responses数组元素 class ActivityResponse { final String activityFieldId; dynamic value; ActivityResponse({required this.activityFieldId, this.value}); // 转换为后端要求的JSON结构 Map<String, dynamic> toJson() { return { 'activity_field_id': activityFieldId, 'value': value, }; } } // 外层提交对象 class FormSubmitPayload { final List<ActivityResponse> activityResponses; FormSubmitPayload({required this.activityResponses}); // 生成最终提交的JSON格式 Map<String, dynamic> toJson() { return { 'activity_responses': activityResponses.map((res) => res.toJson()).toList(), }; } }
2. 用页面状态管理表单输入,替代SharedPreferences
SharedPreferences适合持久化配置,动态表单输入属于页面临时状态,直接用StatefulWidget的状态管理更高效:
class DynamicFormPage extends StatefulWidget { // 从后端拉取的动态表单字段列表(包含activity_field_id、字段名称等信息) final List<dynamic> formFields; const DynamicFormPage({super.key, required this.formFields}); @override State<DynamicFormPage> createState() => _DynamicFormPageState(); } class _DynamicFormPageState extends State<DynamicFormPage> { late List<ActivityResponse> _formResponses; late List<TextEditingController> _inputControllers; @override void initState() { super.initState(); // 初始化响应列表,与后端返回的字段一一对应 _formResponses = widget.formFields.map((field) { return ActivityResponse( activityFieldId: field['activity_field_id'], value: '', // 默认空值,可根据字段类型设置初始值 ); }).toList(); // 为每个字段创建输入控制器,并绑定输入更新逻辑 _inputControllers = List.generate(widget.formFields.length, (index) { final controller = TextEditingController(text: _formResponses[index].value.toString()); // 输入变化时实时更新响应对象的值 controller.addListener(() { setState(() { _formResponses[index].value = controller.text; }); }); return controller; }); } @override void dispose() { // 销毁控制器,避免内存泄漏 for (var controller in _inputControllers) { controller.dispose(); } super.dispose(); } // 提交表单核心逻辑 Future<void> _submitForm() async { // 构建符合要求的提交数据 final payload = FormSubmitPayload(activityResponses: _formResponses); final submitJson = payload.toJson(); // 发送POST请求到后端(替换为你的接口地址) try { final response = await http.post( Uri.parse('https://your-api-url/submit-form'), headers: {'Content-Type': 'application/json'}, body: jsonEncode(submitJson), ); if (response.statusCode == 200) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('提交成功'))); } else { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('提交失败,请重试'))); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('网络错误:$e'))); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('动态表单')), body: Padding( padding: const EdgeInsets.all(16.0), child: ListView.builder( itemCount: widget.formFields.length, itemBuilder: (context, index) { final field = widget.formFields[index]; return TextField( controller: _inputControllers[index], decoration: InputDecoration( labelText: field['field_name'], // 显示后端返回的字段名称 border: const OutlineInputBorder(), ), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: _submitForm, child: const Icon(Icons.send), ), ); } }
3. 扩展适配多类型表单字段
如果表单包含单选框、复选框等非文本输入,只需调整对应组件的状态更新逻辑:
- 单选框:选中时直接更新
_formResponses[index].value为选项值 - 复选框:用
List存储选中值,更新时替换对应的value
内容的提问来源于stack exchange,提问作者clio
相关产品推荐
相关产品推荐

