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

发布于:2025-02-19 ⋅ 阅读:(166) ⋅ 点赞:(0)

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

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 组件,特别是在字段数量和内容不确定的情况下。


网站公告

今日签到

点亮在社区的每一天
去签到