当前位置: 首页 > article >正文

Flutter:动态表单(在不确定字段的情况下,生成动态表单)

关于数据模型:模型就是一种规范约束,便于维护管理,在不确定表单内会出现什么数据时,就没有模型一说。
这时就要用到动态表单(根据接口返回的字段,生成动态表单)

1、观察数据格式,定义模型

modelData:[
	{
		id:1,
		name:'模型一',
		ctaVal:{
  			"first_usdt": {"val": "10", "title": "首仓金额", "unit": "usdt", "read": "0" },
		}
	},
	{
		id:2,
		name:'模型二',
		ctaVal:{
		    "min_profit": {"val": "2", "title": "最小收益率", "unit": "%", "read": "1"}
		}
	}
]


上边自定义的数据格式,已知id和name为固定格式,
ctaVal内的数据不确定具体会返回什么信息,
接口从别的地方抓取的数据,不确定具体字段,
需要动态展示的数据定义:`final Map<String, dynamic> ctaVal;`

class DynamicFormModel {
	int? id;
	String? name;
	final Map<String, dynamic> ctaVal;

  DynamicFormModel ({
    required this.id,
    required this.name,
    required this.ctaVal,
  });

	factory DynamicFormModel .fromJson(Map<String, dynamic> json) {
		return StrategyListModel(
			id: json['id'] as int?,
			name: json['name'] as String?,
			ctaVal: json['ctaVal'] ?? {},
		);
	}

	Map<String, dynamic> toJson() => {
				'id': id,
				'name': name,
				'ctaVal': ctaVal,
			};
}

2、接口处理,请求数据,

// 模型列表
List<DynamicFormModel> modelList = [];
// 当前选中的模型id
int modelId = 0;
// 当前选中的模型
DynamicFormModel? selectedModel;
// 动态表单控制器
final Map<String, TextEditingController> fieldControllers = {};

@override
  void onReady() {
  super.onReady();
  // 获取模型列表、默认模型为第一条数据
  modelList = modelData.map((e) => DynamicFormModel .fromJson(e)).toList();
  if (modelList.isNotEmpty) {
    selectedModel = modelList.first;
    modelController.text = selectedModel?.name ?? '';
    modelId = selectedModel?.id ?? 0;
  }
  update(["strategy_add"]);
}

@override
void onClose() {
  super.onClose();
  // 释放所有控制器
  fieldControllers.forEach((key, controller) {
    controller.dispose();
  });
}

void submit() async{
  // 获取每个字段的值
  for (var entry in fieldControllers.entries) {
    if (entry.value.text.isEmpty) {
      Loading.toast('请输入完整内容');
      return;
    }
  }

  // 收集动态表单内的数据,key=键名(first_usdt)
  Map<String, String> data = {};
  fieldControllers.forEach((key, controller) {
    data[key] = controller.text;
    print('$key,${controller.text}');
  });
  // 如果需要自定义字段 
  data['remark'] = remarkController.text;
  // 转换为 JSON
  String jsonData = jsonEncode(data);
  print('jsonData = $jsonData');
}

3、动态渲染表单页面

// 表单
Widget _buildForm() {
  return GetBuilder<StrategyAddController>(
    id: "strategy_model",
    builder: (_) {
      return <Widget>[
        controller.selectedModel == null
            ? const Center(child: Text('请选择一个模型'))
            : <Widget>[
                ...controller.selectedModel!.ctaVal.entries.map((item) {
                  // 获取或创建控制器
                  final controllerKey = item.key;
                  if (!controller.fieldControllers.containsKey(controllerKey)) {
                    controller.fieldControllers[controllerKey] = TextEditingController(text: item.value['val']);
                  }
                  final fieldController = controller.fieldControllers[controllerKey];
                  return <Widget>[
                    InputWidget(
                      prefix: TextWidget.body(
                        item.value['title'],
                      ),
                      placeholder: item.value['read'] == '1'
                          ? ""
                          : '请输入${item.value['title']}',
                      controller:fieldController,
                      readOnly: item.value['read'] == '1' ? true : false,
                    ).expanded(),
                    TextWidget.body(
                      item.value['unit'],
                    ),
                  ].toRow(crossAxisAlignment: CrossAxisAlignment.center).opacity(item.value['read'] == '1' ? 0.5 : 1);
                }),

              ].toColumn(crossAxisAlignment: CrossAxisAlignment.start)
      ].toColumn();
    },
  );
}

...controller.selectedModel!.ctaVal.entries.map((item) => ...) 会遍历 ctaVal 中的每个条目,并将其映射为一个新的 Widget 列表。
每个 item 是一个 MapEntry,可以通过 item.keyitem.value 访问键和值。
这种方式非常适合动态生成 UI 组件,特别是在字段数量和内容不确定的情况下。


http://www.kler.cn/a/550999.html

相关文章:

  • Electron 客户端心跳定时任务调度库调研文档 - Node.js 任务调度库技术调研文档
  • Java 不可变集合
  • 【市场问题排查神器-arthas】
  • 鸿蒙UI开发——隐私遮罩效果
  • 百度百舸 DeepSeek 一体机发布,支持昆仑芯 P800 单机 8 卡满血版开箱即用
  • Springboot RabbitMQ 消费失败消息清洗与重试机制
  • 【Python网络爬虫】爬取网站图片实战
  • 智能马达保护器:为工业电机安全运行保驾护航
  • 《解锁自然语言处理:让公众正确拥抱AI语言魔法》
  • Natural Language Processing NLP
  • STM32外设SPI FLASH应用实例
  • STM32 低功耗模式
  • 【前端学习笔记】Webpack
  • Letsencrypt+certbot为域名免费配置ssl
  • 【漫话机器学习系列】095.决策边界(Decision Boundary)
  • 静态页面在安卓端可以正常显示,但是在ios打开这个页面就需要刷新才能显示全图片
  • HTTP 和 TCP/IP-傻傻分不清
  • C#之上位机开发---------C#通信库及WPF的简单实践
  • mysql 使用 CONCAT、GROUP_CONCAT 嵌套查询出 json 格式数据
  • 瑞萨RA-T系列芯片ADCGPT功能模块的配合使用