Flutter Web中弹窗显示时如何处理浏览器返回按钮?
解决方案:拦截GoRouter路由pop以关闭弹窗
问题根源:浏览器返回按钮触发的是GoRouter管理的路由栈pop,而弹窗属于Flutter本地Navigator的弹窗,不在GoRouter的路由栈中。你之前将PopScope包裹在弹窗内部,只能监听弹窗自身的本地pop操作(如点击关闭按钮),无法拦截GoRouter的路由级pop事件。
修改方案
在Page2页面外层使用PopScope,监听路由级别的pop请求,判断弹窗是否处于打开状态:
- 若弹窗打开:优先关闭弹窗,阻止路由返回
- 若弹窗关闭:正常执行路由返回
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { MyApp({super.key}); final GoRouter _router = GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const Page1(), ), GoRoute( path: '/page2', builder: (context, state) => const Page2(), ), ], ); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: _router, ); } } class Page1 extends StatelessWidget { const Page1({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Page 1')), body: Center( child: ElevatedButton( onPressed: () { context.go('/page2'); }, child: const Text('goto Page 2'), ), ), ); } } class Page2 extends StatefulWidget { const Page2({super.key}); @override State<Page2> createState() => _Page2State(); } class _Page2State extends State<Page2> { // 标记弹窗是否打开 bool _isDialogOpen = false; @override Widget build(BuildContext context) { // 在页面外层包裹PopScope,监听路由级pop事件 return PopScope( // 弹窗打开时,禁止路由pop canPop: !_isDialogOpen, onPopInvokedWithResult: (didPop, result) { if (_isDialogOpen) { // 关闭弹窗 Navigator.of(context).pop(); setState(() { _isDialogOpen = false; }); } else { // 正常返回上路由 context.pop(); } }, child: Scaffold( appBar: AppBar(title: const Text('Page 2')), body: Center( child: ElevatedButton( onPressed: () async { setState(() { _isDialogOpen = true; }); // 等待弹窗关闭后更新状态 await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Dialog'), content: const Text('Dialog content'), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); setState(() { _isDialogOpen = false; }); print('Close button clicked'); }, child: const Text('Close'), ), ], ); }, ); // 弹窗关闭后确保状态更新(处理点击弹窗外部关闭的情况) setState(() { _isDialogOpen = false; }); }, child: const Text('Open dialog'), ), ), ), ); } }
关键修改点
- 将
Page2改为StatefulWidget,添加_isDialogOpen状态标记弹窗状态 - 在
Page2外层包裹PopScope,监听路由级pop事件 - 弹窗打开时设置
canPop: false,阻止路由返回;关闭时恢复为true - 在
onPopInvokedWithResult中判断弹窗状态,优先关闭弹窗 - 处理弹窗关闭后的状态更新(包括点击关闭按钮和点击弹窗外部关闭的情况)
内容的提问来源于stack exchange,提问作者mlapeyre
相关产品推荐
相关产品推荐

