Flutter Navigator 2.0中Android返回键直接退出APP而非回退路由问题
问题现象
- 点击
AppBar返回按钮时,页面可正常按层级回退:Second Page ---> pop --- | │ | ↓ First Page First Page ---> pop --- | | │ | | ↓ Main Page Main Page Main Page - 按下/滑动Android物理返回键时,应用直接关闭,不执行路由回退:
Second Page ---> Android back btn pop --- | │ | | First Page | | | | ↓ Main Page App is closed
现象演示:
简化版复现代码
import 'package:flutter/material.dart'; void main() { runApp(const MainApp()); } class MainApp extends StatelessWidget { const MainApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Router( routerDelegate: AppRouterDelegate(), backButtonDispatcher: RootBackButtonDispatcher(), ), ); } } class MainPage extends StatelessWidget { const MainPage({super.key, required this.openFirstPage}); final VoidCallback openFirstPage; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Main page'), backgroundColor: Colors.lightGreen, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Welcome to main page!'), ElevatedButton( onPressed: openFirstPage, child: const Text('Go to first page'), ), ], ), ), ); } } class FirstPage extends StatelessWidget { const FirstPage({super.key, required this.openSecondPage}); final VoidCallback openSecondPage; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('First page'), backgroundColor: Colors.amber, ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Welcome to first page!'), ElevatedButton( onPressed: openSecondPage, child: const Text('Go to second page'), ), ], ), ), ); } } class SecondPage extends StatelessWidget { const SecondPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Second page'), backgroundColor: Colors.lightBlueAccent, ), body: const Center( child: Text('Welcome to second page!'), ), ); } } class AppRouterDelegate extends RouterDelegate with ChangeNotifier, PopNavigatorRouterDelegateMixin { bool _showFirstPage = false; void showFirstPage() { _showFirstPage = true; notifyListeners(); } bool _showSecondPage = false; void showSecondPage() { _showSecondPage = true; notifyListeners(); } @override Widget build(BuildContext context) { return Navigator( key: navigatorKey, pages: [ MaterialPage( key: const ValueKey('MainPage'), child: MainPage(openFirstPage: showFirstPage), ), if (_showFirstPage) MaterialPage( key: const ValueKey('FirstPage'), child: FirstPage(openSecondPage: showSecondPage), ), if (_showSecondPage) const MaterialPage( key: ValueKey('SecondPage'), child: SecondPage(), ), ], onDidRemovePage: (page) { if (_showSecondPage) { _showSecondPage = false; return; } if (_showFirstPage) _showFirstPage = false; }, ); } @override GlobalKey<NavigatorState>? get navigatorKey => GlobalKey(); @override Future<void> setNewRoutePath(configuration) async { // Do nothing } }
问题原因
使用RootBackButtonDispatcher会直接将物理返回键事件传递给系统,跳过RouterDelegate的路由处理逻辑,触发系统默认的“关闭应用”行为,而非执行页面回退。
解决方案
步骤1:替换返回键调度器
将RootBackButtonDispatcher替换为ChildBackButtonDispatcher,并让其优先处理返回事件,确保路由代理能捕获到物理返回键事件:
修改MainApp的build方法:
@override Widget build(BuildContext context) { final routerDelegate = AppRouterDelegate(); return MaterialApp( home: Router( routerDelegate: routerDelegate, backButtonDispatcher: ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher!) ..takePriority(), ), ); }
步骤2:实现路由回退逻辑
在AppRouterDelegate中重写popRoute方法,按路由层级处理回退:
@override Future<bool> popRoute() { // 先回退第二页 if (_showSecondPage) { _showSecondPage = false; notifyListeners(); return Future.value(true); } // 再回退第一页 if (_showFirstPage) { _showFirstPage = false; notifyListeners(); return Future.value(true); } // 无路由可回退时,返回false让系统处理(关闭应用) return Future.value(false); }
修改后,物理返回键会按照路由层级依次回退页面,只有当没有可回退路由时才会关闭应用。
内容的提问来源于stack exchange,提问作者sm-sayedi
相关产品推荐
相关产品推荐

