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
相关产品推荐
相关产品推荐

