Flutter基于实体类动态构建表单并生成正确类型JSON提交
问题描述
我有一个用于处理Web服务JSON数据的实体类,定义如下:
class BuildingSiteVisits { int? id; String? name; double? lat; // 注:Dart中无Float类型,实际应使用double double? long; BuildingSiteVisits({this.id, this.name, this.lat, this.long}); BuildingSiteVisits.fromJson(Map<String, dynamic> json) { id = json['id']; name = json['name']; lat = json['lat']; long = json['long']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['id'] = id; data['name'] = name; data['lat'] = lat; data['long'] = long; return data; } }
我需要为类中每个字段生成对应的TextField动态构建表单,提交时生成格式正确的JSON(数字不带引号、字符串带引号)。目前通过字符串列表定义字段并构建表单:
const List<String> buildingsiteFields = ['id','name','long','lat'];
表单构建代码:
Widget _listView(List<String> fieldlist) { return ListView.builder( itemCount: fieldlist.length, itemBuilder: (context, index) { _controllers[fieldlist[index]] = TextEditingController(); return Container( margin: const EdgeInsets.all(5), child: buildTextEditField( textEdetingController: _controllers[fieldlist[index]] ?? TextEditingController(), label: fieldlist[index]), ); }, ); } final Map<String, TextEditingController> _controllers = {};
当前生成JSON的方式会把所有字段转成字符串,导致Web服务无法正确处理:
return ElevatedButton( onPressed: () async { var text = '{'; _controllers.forEach((key, value) { text = '$text"$key":"${value.text}",'; }); text = text.substring(0, text.length - 1); text = '$text}'; postData(dataTable: tableBuildingSiteVisit, jsonBody: text); setState(() {}); }, );
请问如何基于这个实体类构建表单,并将输入值转换为对应类型(int、double、String等),生成格式正确的JSON提交?
解决方案
步骤1:定义字段与类型映射
先明确每个字段对应的类型,为后续值转换做基础:
final Map<String, Type> _fieldTypes = { 'id': int, 'name': String, 'lat': double, 'long': double, // 其他字段按实际类型添加 };
步骤2:优化表单构建(可选)
根据字段类型设置对应键盘类型,提升输入体验:
Widget _listView(List<String> fieldlist) { return ListView.builder( itemCount: fieldlist.length, itemBuilder: (context, index) { final fieldName = fieldlist[index]; _controllers[fieldName] = TextEditingController(); TextInputType? keyboardType; if (_fieldTypes[fieldName] == int) { keyboardType = TextInputType.number; } else if (_fieldTypes[fieldName] == double) { keyboardType = TextInputType.numberWithOptions(decimal: true); } return Container( margin: const EdgeInsets.all(5), child: TextField( controller: _controllers[fieldName], keyboardType: keyboardType, decoration: InputDecoration( labelText: fieldName, border: const OutlineInputBorder(), ), ), ); }, ); }
步骤3:正确转换值并生成标准JSON
核心思路是:将输入文本按字段类型转换后,实例化实体类,再调用其toJson()方法生成标准JSON:
return ElevatedButton( onPressed: () async { final buildingSite = BuildingSiteVisits(); _controllers.forEach((key, controller) { final inputText = controller.text.trim(); if (inputText.isEmpty) return; // 空值可根据需求处理 switch (_fieldTypes[key]) { case int: buildingSite.id = int.tryParse(inputText); break; case String: buildingSite.name = inputText; break; case double: if (key == 'lat') { buildingSite.lat = double.tryParse(inputText); } else if (key == 'long') { buildingSite.long = double.tryParse(inputText); } break; // 其他字段类型按此模式扩展 } }); // 生成标准JSON字符串 final jsonBody = jsonEncode(buildingSite.toJson()); postData(dataTable: tableBuildingSiteVisit, jsonBody: jsonBody); setState(() {}); }, );
进阶优化:用反射简化多字段赋值
如果实体类字段较多,手动写switch会繁琐,可使用Dart反射包reflectable自动处理:
- 添加依赖到
pubspec.yaml:
dependencies: reflectable: ^4.0.6
- 创建反射配置文件
reflectable_config.dart:
import 'package:reflectable/reflectable.dart'; class Reflector extends Reflectable { const Reflector() : super( instanceInvokeCapability, metadataCapability, typeCapability, ); } const reflector = Reflector();
- 为实体类添加反射注解:
import 'reflectable_config.dart'; @reflector class BuildingSiteVisits { // 原类定义不变 }
- 用反射自动赋值:
// 替换按钮点击事件中的switch逻辑 final instanceMirror = reflector.reflect(buildingSite); _controllers.forEach((key, controller) { final inputText = controller.text.trim(); if (inputText.isEmpty) return; final fieldType = _fieldTypes[key]; dynamic value; if (fieldType == int) { value = int.tryParse(inputText); } else if (fieldType == double) { value = double.tryParse(inputText); } else if (fieldType == String) { value = inputText; } if (value != null) { instanceMirror.setField(key, value); } });
内容的提问来源于stack exchange,提问作者fisi-pjm
相关产品推荐
相关产品推荐

