You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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自动处理:

  1. 添加依赖到pubspec.yaml:
dependencies:
  reflectable: ^4.0.6
  1. 创建反射配置文件reflectable_config.dart:
import 'package:reflectable/reflectable.dart';

class Reflector extends Reflectable {
  const Reflector() : super(
    instanceInvokeCapability,
    metadataCapability,
    typeCapability,
  );
}

const reflector = Reflector();
  1. 为实体类添加反射注解:
import 'reflectable_config.dart';

@reflector
class BuildingSiteVisits {
  // 原类定义不变
}
  1. 用反射自动赋值:
// 替换按钮点击事件中的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 01:28:19