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

Flutter实现样本对应表单切换遇阻,求可行解决方案

Flutter 样本表单切换实现方案

核心问题分析

你遇到的问题本质是表单状态隔离和视图切换同步的问题:Stack/IndexedStack需要每个表单拥有独立状态Key,GetX则需要确保选中状态和表单数据正确绑定,否则会出现切换后表单状态混乱或不刷新的情况。

方案一:GetX 实现(推荐)

通过GetX管理选中状态,为每个样本分配独立的表单Key和数据存储,确保切换时状态不串位。

1. 编写表单控制器

class SampleFormController extends GetxController {
  // 当前选中的样本索引
  final selectedIndex = 0.obs;
  // 存储每个样本的表单Key和对应数据
  final List<Map<String, dynamic>> samples = [
    {'formKey': GlobalKey<FormBuilderState>(), 'data': {}},
    {'formKey': GlobalKey<FormBuilderState>(), 'data': {}},
    // 按需添加更多样本初始化数据
  ];

  // 切换选中样本
  void selectSample(int index) {
    selectedIndex.value = index;
  }
}

2. 实现页面布局

class SampleFormPage extends StatelessWidget {
  final controller = Get.put(SampleFormController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('样本表单切换')),
      body: Row(
        children: [
          // 样本列表区域
          Expanded(
            flex: 1,
            child: ListView.builder(
              itemCount: controller.samples.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('样本 ${index + 1}'),
                  selected: controller.selectedIndex.value == index,
                  onTap: () => controller.selectSample(index),
                );
              },
            ),
          ),
          // 表单显示区域
          Expanded(
            flex: 2,
            child: Obx(() {
              final currentSample = controller.samples[controller.selectedIndex.value];
              return FormBuilder(
                key: currentSample['formKey'],
                initialValue: currentSample['data'],
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    children: [
                      FormBuilderTextField(
                        name: 'field1',
                        decoration: const InputDecoration(labelText: '字段1'),
                        onChanged: (value) => currentSample['data']['field1'] = value,
                      ),
                      FormBuilderTextField(
                        name: 'field2',
                        decoration: const InputDecoration(labelText: '字段2'),
                        onChanged: (value) => currentSample['data']['field2'] = value,
                      ),
                      const SizedBox(height: 20),
                      ElevatedButton(
                        onPressed: () {
                          currentSample['formKey'].currentState?.save();
                          print('当前样本数据:${currentSample['data']}');
                        },
                        child: const Text('保存表单'),
                      )
                    ],
                  ),
                ),
              );
            }),
          ),
        ],
      ),
    );
  }
}

方案二:IndexedStack 实现

如果更倾向于原生状态管理,IndexedStack可以保留所有表单状态,只需确保每个表单的Key唯一。

class SampleFormPage extends StatefulWidget {
  @override
  State<SampleFormPage> createState() => _SampleFormPageState();
}

class _SampleFormPageState extends State<SampleFormPage> {
  int selectedIndex = 0;
  // 每个样本对应独立的表单Key
  final List<GlobalKey<FormBuilderState>> formKeys = [
    GlobalKey<FormBuilderState>(),
    GlobalKey<FormBuilderState>(),
  ];
  // 每个样本的表单数据单独存储
  final List<Map<String, dynamic>> formData = [{}, {}];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('样本表单切换')),
      body: Row(
        children: [
          Expanded(
            flex: 1,
            child: ListView.builder(
              itemCount: formKeys.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('样本 ${index + 1}'),
                  selected: selectedIndex == index,
                  onTap: () => setState(() => selectedIndex = index),
                );
              },
            ),
          ),
          Expanded(
            flex: 2,
            child: IndexedStack(
              index: selectedIndex,
              children: List.generate(formKeys.length, (index) {
                return FormBuilder(
                  key: formKeys[index],
                  initialValue: formData[index],
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      children: [
                        FormBuilderTextField(
                          name: 'field1',
                          decoration: const InputDecoration(labelText: '字段1'),
                          onChanged: (value) => formData[index]['field1'] = value,
                        ),
                        FormBuilderTextField(
                          name: 'field2',
                          decoration: const InputDecoration(labelText: '字段2'),
                          onChanged: (value) => formData[index]['field2'] = value,
                        ),
                        const SizedBox(height: 20),
                        ElevatedButton(
                          onPressed: () {
                            formKeys[index].currentState?.save();
                            print('当前样本数据:${formData[index]}');
                          },
                          child: const Text('保存表单'),
                        )
                      ],
                    ),
                  ),
                );
              }),
            ),
          ),
        ],
      ),
    );
  }
}

关键注意事项

  • 表单Key必须独立:每个样本的FormBuilder必须使用唯一的GlobalKey<FormBuilderState>,否则会导致多个表单共用状态,出现输入串位问题。
  • 数据单独存储:每个样本的表单数据要单独维护,切换时才能保留已填写的内容。
  • GetX方案中,必须用Obx包裹表单区域,确保选中状态变化时自动刷新视图。

内容的提问来源于stack exchange,提问作者Tareq khashaneh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:32:50