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

Flutter页面双向传值问题:复用表单页编辑列表数据

解决方案:复用表单页实现新建/编辑功能且不影响原有调用

问题背景

现有两个页面:TrainingCreateScreen(表单页,用于新建Exercise并加入training_list)和WorkoutReviewScreen(列表页,展示所有Exercise)。需要在列表页点击编辑按钮时,复用表单页填充待编辑对象的信息,编辑完成后更新列表;同时要保证其他页面调用表单页时无需传递参数。

具体实现步骤

1. 给TrainingCreateScreen添加可选参数的构造函数

在TrainingCreateScreen类中添加可选的exerciseToEdit和trainingList参数,既支持编辑场景传值,也兼容新建场景的无参数调用:

class TrainingCreateScreen extends StatefulWidget {
  // 可选参数:编辑时传入待修改的Exercise和对应列表
  final Exercise? exerciseToEdit;
  final List<Exercise>? trainingList;

  // 构造函数:默认参数为null,适配新建场景
  const TrainingCreateScreen({super.key, this.exerciseToEdit, this.trainingList});

  @override
  _TrainingCreateScreenState createState() => _TrainingCreateScreenState();
}

2. 在State类中初始化表单控制器并填充编辑数据

补全缺失的文本控制器,在initState中判断是否为编辑模式,自动填充表单数据:

class _TrainingCreateScreenState extends State<TrainingCreateScreen> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  // 补全所有表单控制器
  final _exerciseName = TextEditingController();
  final _numberOfSets = TextEditingController();
  final _numberOfReps = TextEditingController();
  final _exerciseRPE = TextEditingController();
  final _exerciseNotes = TextEditingController();

  @override
  void initState() {
    super.initState();
    // 编辑模式下填充已有数据
    if (widget.exerciseToEdit != null) {
      final exercise = widget.exerciseToEdit!;
      _exerciseName.text = exercise.name;
      _numberOfSets.text = exercise.sets.toString();
      _numberOfReps.text = exercise.reps.toString();
      _exerciseRPE.text = exercise.rpe.toString();
      _exerciseNotes.text = exercise.notes;
    }
  }

  @override
  void dispose() {
    // 销毁控制器避免内存泄漏
    _exerciseName.dispose();
    _numberOfSets.dispose();
    _numberOfReps.dispose();
    _exerciseRPE.dispose();
    _exerciseNotes.dispose();
    super.dispose();
  }

  // 原有build及其他方法...
}

3. 修改添加按钮逻辑,区分新建/编辑模式

调整buildExerciseBt的点击事件,判断当前模式:编辑时替换原对象,新建时添加新对象,完成后返回列表页:

Widget buildExerciseBt() {
  return FloatingActionButton(
    onPressed: () {
      if (_formKey.currentState!.validate()) {
        final updatedExercise = Exercise(
          _exerciseName.text,
          int.tryParse(_numberOfSets.text) ?? 0,
          int.tryParse(_numberOfReps.text) ?? 0,
          int.tryParse(_exerciseRPE.text) ?? 0,
          _exerciseNotes.text.isEmpty ? '' : _exerciseNotes.text,
        );

        if (widget.exerciseToEdit != null && widget.trainingList != null) {
          // 编辑模式:替换列表中的原对象
          final index = widget.trainingList!.indexOf(widget.exerciseToEdit!);
          if (index != -1) {
            widget.trainingList![index] = updatedExercise;
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text("Exercise updated")),
            );
            Navigator.pop(context);
          }
        } else {
          // 新建模式:添加新对象到列表
          training_list.add(updatedExercise);
          final snAdded = SnackBar(
            content: const Text("Added to the workout"),
            action: SnackBarAction(
              label: "undo",
              onPressed: () => training_list.removeLast(),
            ),
          );
          ScaffoldMessenger.of(context).showSnackBar(snAdded);
        }
      }
    },
    backgroundColor: Colors.amber,
    child: const Icon(Icons.add),
  );
}

4. 修正WorkoutReviewScreen的编辑跳转代码

跳转表单页时传递待编辑对象和列表,返回后刷新列表:

Widget buildEditExerciseBt(Exercise editExercise) {
  return IconButton(
    onPressed: () {
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => TrainingCreateScreen(
            exerciseToEdit: editExercise,
            trainingList: widget.training_list,
          ),
        ),
      ).then((_) => setState(() {})); // 返回后刷新列表
    },
    icon: const Icon(Icons.edit),
  );
}

5. 修复列表页的数据源引用问题

将ListView的itemCount和数据源改为使用widget.training_list,避免全局变量的不一致问题:

body: ListView.builder(
  padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 10),
  itemCount: widget.training_list.length,
  itemBuilder: (context, index) => Container(
    margin: const EdgeInsets.symmetric(vertical: 3),
    child: exersiceCard(widget.training_list[index]),
  ),
),

关键说明

  • 可选参数构造函数完美兼容新建、编辑两种场景,无需额外创建页面
  • 编辑完成后通过Navigator.pop返回列表页,调用setState刷新最新数据
  • 控制器在initState初始化、dispose销毁,符合Flutter生命周期规范

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 06:06:05