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

Flutter中showModalBottomSheet无法同步父组件更新后状态怎么办?

问题根源

showModalBottomSheet 是 Flutter 的路由级弹窗,默认和父组件的更新逻辑隔离,父组件调用 setState 只会刷新自身 Widget 树,不会触发已打开弹窗的重绘。同时你当前使用的 NewToDo 是无状态组件,内部没有监听输入控制器的变化,输入内容更新后无法主动刷新按钮状态,才会出现输入后按钮仍然禁用的问题。

解决方案

一共需要修改两处代码即可解决:

1. 修改 NewToDo.dart 为有状态组件,监听输入变化触发重绘

将原来的无状态 NewToDo 改为有状态组件,监听两个输入控制器的变化,输入内容更新时主动刷新组件:

import 'package:flutter/material.dart';
import './classes/todo.dart';

class NewToDo extends StatefulWidget {
  final Function addTodo;
  final Function clear;
  final ToDo? todo;
  final TextEditingController titleController;
  final TextEditingController contentController;

  const NewToDo(this.titleController, this.contentController, this.addTodo, this.clear, this.todo, {Key? key}) : super(key: key);

  @override
  State<NewToDo> createState() => _NewToDoState();
}

class _NewToDoState extends State<NewToDo> {
  @override
  void initState() {
    super.initState();
    // 监听输入框变化,触发当前组件重绘
    widget.titleController.addListener(_refresh);
    widget.contentController.addListener(_refresh);
  }

  void _refresh() {
    setState(() {});
  }

  @override
  void dispose() {
    // 移除监听避免内存泄漏
    widget.titleController.removeListener(_refresh);
    widget.contentController.removeListener(_refresh);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          decoration: const InputDecoration(
            labelText: 'Title',
          ),
          controller: widget.titleController,
          autofocus: true,
        ),
        TextField(
          decoration: const InputDecoration(
            labelText: 'Details',
          ),
          controller: widget.contentController,
          autofocus: true,
        ),
        ButtonBar(
            alignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: widget.titleController.text.isNotEmpty ? () => widget.addTodo() : null,
                child: Text(widget.todo != null ? '编辑待办' : '添加待办'),
                style: ButtonStyle(
                  backgroundColor: widget.titleController.text.isNotEmpty ? MaterialStateProperty.all<Color>(Colors.deepPurple) : null,
                  overlayColor: MaterialStateProperty.all<Color>(Colors.purple),
                ),
              ),
              Visibility (
                visible: widget.titleController.text.isNotEmpty || widget.contentController.text.isNotEmpty,
                child: ElevatedButton(
                  onPressed: () => widget.clear(),
                  child: const Text('清空'),
                )),
            ])
      ],
    );
  }
}

2. 弹窗嵌套 StatefulBuilder 同步父组件状态

如果需要父组件状态(比如编辑时传入的待办数据 _todo)更新时,已打开的弹窗能同步刷新,就用 StatefulBuilder 包裹弹窗的返回内容,修改 main.dart 里的 showModalBottomSheet 部分:

floatingActionButton: FloatingActionButton(
  onPressed: () {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (context, setModalState) {
            return Container(
              child: NewToDo(titleController, contentController, _addTodo, _clear, _todo),
            );
          },
        );
      });
  },
  child: const Icon(Icons.add),
  backgroundColor: Colors.deepPurple,
),

修改完成后,输入内容变化时按钮状态会实时更新,父组件的待办编辑数据也能同步到已打开的弹窗中,无需关闭弹窗重新打开。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:24:04