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

Flutter:如何在showModalBottomSheet关闭前弹出确认对话框?

解决Flutter showModalBottomSheet关闭前确认及编辑状态控制问题

核心思路

  1. 用状态管理跟踪编辑内容是否变更(标记为_isDirty),仅当内容变更时显示保存按钮,避免频繁序列化写入数据库。
  2. 通过WillPopScope拦截系统返回操作,结合自定义背景点击处理,实现关闭前的确认逻辑。

完整代码实现

void showEditBottomSheet(BuildContext context, String initialData) {
  showModalBottomSheet(
    context: context,
    isDismissible: false, // 禁用默认背景点击关闭,自行处理
    builder: (context) => EditBottomSheet(initialData: initialData),
  );
}

class EditBottomSheet extends StatefulWidget {
  final String initialData;

  const EditBottomSheet({super.key, required this.initialData});

  @override
  State<EditBottomSheet> createState() => _EditBottomSheetState();
}

class _EditBottomSheetState extends State<EditBottomSheet> {
  late String _editedData;
  bool _isDirty = false;

  @override
  void initState() {
    super.initState();
    _editedData = widget.initialData;
  }

  // 执行保存操作
  void _saveChanges() {
    // 这里写入数据库逻辑
    // ...
    setState(() {
      _isDirty = false;
    });
    Navigator.pop(context); // 保存完成后关闭弹窗
  }

  // 关闭前的确认逻辑
  Future<bool> _confirmClose() async {
    if (!_isDirty) return true; // 无修改直接允许关闭

    final result = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('确认关闭'),
        content: const Text('未保存的修改将会丢失,确定要关闭吗?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, false),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () => Navigator.pop(context, true),
            child: const Text('确定'),
          ),
        ],
      ),
    );

    return result ?? false;
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: _confirmClose, // 拦截系统返回键
      child: GestureDetector(
        onTap: () async {
          // 处理背景点击事件
          final canClose = await _confirmClose();
          if (canClose) {
            Navigator.pop(context);
          }
        },
        child: Container(
          color: Colors.transparent, // 透明背景让手势监听生效
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: TextField(
                  controller: TextEditingController(text: _editedData),
                  onChanged: (value) {
                    setState(() {
                      _editedData = value;
                      _isDirty = value != widget.initialData;
                    });
                  },
                  decoration: const InputDecoration(hintText: '编辑内容'),
                ),
              ),
              // 仅当内容变更时显示保存按钮
              if (_isDirty)
                Padding(
                  padding: const EdgeInsets.only(bottom: 16.0, right: 16.0),
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: ElevatedButton(
                      onPressed: _saveChanges,
                      child: const Text('保存'),
                    ),
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }
}

关键细节说明

  • 状态跟踪:通过_isDirty标记内容是否与初始值不同,仅在标记为true时渲染保存按钮,避免无意义的数据库操作。
  • 关闭拦截:
    • WillPopScope拦截Android物理返回键、iOS侧滑返回等系统级关闭操作,触发确认弹窗。
    • 禁用showModalBottomSheet的默认背景关闭逻辑,通过最外层GestureDetector监听背景点击,统一走确认流程。
  • 确认逻辑:弹出警告对话框,仅在用户明确确认放弃修改后,才执行Navigator.pop关闭底部弹窗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:03:31