Flutter Router如何同时处理系统返回键与AppBar返回并弹出确认模态框
你的实现思路的核心问题在于 onPopPage 是路由pop操作执行完成后的回调,只能处理pop后的收尾逻辑,无法在pop动作执行前做拦截,所以没办法在这里插入确认弹窗逻辑。
方案一:路由层统一拦截(推荐)
这种方案将所有返回拦截逻辑放在AppRouterDelegate中统一处理,系统返回键和AppBar返回按钮走完全相同的逻辑,不会出现两端行为不一致的问题。
步骤1:修改AppRouterDelegate的popRoute方法
这里是系统返回键的触发入口,我们先判断当前是否在需要拦截的页面,是的话先弹出确认框,用户确认后再执行pop操作:
@override Future<bool> popRoute() async { final NavigatorState? navigator = navigatorKey.currentState; if (navigator == null) return SynchronousFuture<bool>(false); // 判断当前是否在需要拦截的新建产品页 if (appNotifier.newItem) { // 弹出确认对话框 final bool? confirm = await showDialog<bool>( context: navigator.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('确认退出'), ), ], ), ); // 用户确认退出才执行后续逻辑 if (confirm == true) { appNotifier.setNewItem(false); return SynchronousFuture(true); } // 用户取消,拦截返回操作 return SynchronousFuture(false); } // 其他页面走默认返回逻辑 return navigator.maybePop(); }
步骤2:简化onPopPage逻辑
因为我们已经在popRoute中处理了状态修改和拦截逻辑,onPopPage只需要保留基础逻辑即可:
onPopPage: (route, result) { if (!route.didPop(result)) return false; return true; },
步骤3:修改ProductAddPage的返回按钮逻辑
让AppBar的返回按钮直接调用Router的pop方法,和系统返回键走同一套处理逻辑:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("添加产品"), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { // 触发RouterDelegate的popRoute逻辑,和系统返回键完全统一 Router.of(context).pop(); }, ), ), // 页面其他内容 ); }
方案二:页面层WillPopScope拦截
如果只有少量页面需要拦截,也可以在页面层通过WillPopScope实现,耦合度更低:
@override Widget build(BuildContext context) { return WillPopScope( // 拦截系统返回键 onWillPop: () async { final bool? confirm = 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 confirm ?? false; }, child: Scaffold( appBar: AppBar( title: const Text("添加产品"), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () async { // 调用和系统返回键相同的拦截逻辑 await Navigator.of(context).maybePop(); // 确认返回后修改状态 if (context.mounted) { context.read<AppNotifier>().setNewItem(false); } }, ), ), // 页面其他内容 ), ); }
这种方案不需要修改AppRouterDelegate的原有逻辑,适合页面拦截逻辑差异较大的场景。
内容的提问来源于stack exchange,提问作者Sa231asd3
相关产品推荐
相关产品推荐

