Flutter应用Android返回按钮/手势触发直接退出应用问题求助
Flutter Android返回按钮/手势异常:跳转后返回直接退出应用
在Flutter应用的Android平台上,从Welcome Screen通过Navigator.pushNamed跳转到Login Screen后,点击返回按钮或触发返回手势,本该回到Welcome Screen,但应用直接退出。以下是相关代码及修复方案:
相关代码
路由类(AppRouter)
class AppRouter { Route<dynamic>? onGenerateRoute(RouteSettings routeSettings) { switch (routeSettings.name) { case '/login': return PageRouteBuilder( settings: routeSettings, pageBuilder: (_, __, ___) { return const LoginScreen(); }, transitionDuration: const Duration(milliseconds: 600), reverseTransitionDuration: const Duration(milliseconds: 450), transitionsBuilder: (_, a, __, c) => SlideTransition( position: Tween<Offset>( begin: const Offset(1.0, 0.0), end: Offset.zero, ).animate( CurvedAnimation( parent: a, curve: Curves.easeInOutCubicEmphasized, ), ), child: c)); default: return _materialRoute(const WelcomeScreen()); } } static Route<dynamic> _materialRoute(Widget view) { return MaterialPageRoute(builder: (_) => view); } }
main.dart
class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, ); return ScreenUtilInit( designSize: const Size(430, 932), minTextAdapt: true, splitScreenMode: true, builder: (_, child) { return MaterialApp( home: Navigator( key: navigatorKey, onGenerateRoute: AppRouter().onGenerateRoute, ), ); }); } }
Welcome Screen
class WelcomeScreen extends StatefulWidget { const WelcomeScreen({super.key}); @override State<StatefulWidget> createState() { return _WelcomeScreenState(); } } class _WelcomeScreenState extends State<WelcomeScreen> { @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: [ SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { Navigator.of(context).pushNamed('/login'); }, child: const Text('Continue with E-Mail'), ), ), const SizedBox( height: 12, ), ], ), ), ), ); } }
Login Screen
class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override State<StatefulWidget> createState() { return _LoginScreenState(); } } class _LoginScreenState extends State<LoginScreen> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return PopScope( canPop: true, onPopInvoked: (didPop) => print('onPopInvoked didPop? $didPop'), child: Scaffold( appBar: AppBar( toolbarHeight: 0.09.sh, leadingWidth: 70, leading: Padding( padding: const EdgeInsets.only(left: 20), child: GestureDetector( onTap: () { Navigator.of(context).pushReplacementNamed('/welcome'); }, child: SvgPicture.asset( 'assets/icons/back-in-circle.svg', fit: BoxFit.contain, color: Theme.of(context).brightness == Brightness.light ? colorBlack : null, ), ), )), body: SafeArea( child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.max, children: [ Text("Login screen") ], ), ), ), ), ); } }
AndroidManifest.xml配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <application ... <activity ... android:enableOnBackInvokedCallback="true">
效果说明
- 当前效果:从Login Screen返回时直接退出应用
- 预期效果:从Login Screen返回时回到Welcome Screen
问题根源
MaterialApp直接将Navigator作为home属性,相当于在MaterialApp自带的导航栈之外嵌套了一层独立导航栈。Android系统的返回手势/按钮只会识别外层导航栈的状态,当Login Screen弹出后,外层栈仅存一个页面,因此触发返回时直接退出应用。
修复方案
1. 调整main.dart的导航配置
移除嵌套的Navigator,改用MaterialApp自带的导航管理,指定初始路由:
class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, ); return ScreenUtilInit( designSize: const Size(430, 932), minTextAdapt: true, splitScreenMode: true, builder: (_, child) { return MaterialApp( navigatorKey: navigatorKey, initialRoute: '/welcome', // 指定初始路由 onGenerateRoute: AppRouter().onGenerateRoute, ); }); } }
2. 完善路由规则
在AppRouter中添加/welcome的明确路由分支,避免default分支的歧义:
class AppRouter { Route<dynamic>? onGenerateRoute(RouteSettings routeSettings) { switch (routeSettings.name) { case '/welcome': return _materialRoute(const WelcomeScreen()); case '/login': return PageRouteBuilder( settings: routeSettings, pageBuilder: (_, __, ___) { return const LoginScreen(); }, transitionDuration: const Duration(milliseconds: 600), reverseTransitionDuration: const Duration(milliseconds: 450), transitionsBuilder: (_, a, __, c) => SlideTransition( position: Tween<Offset>( begin: const Offset(1.0, 0.0), end: Offset.zero, ).animate( CurvedAnimation( parent: a, curve: Curves.easeInOutCubicEmphasized, ), ), child: c)); default: return _materialRoute(const WelcomeScreen()); } } static Route<dynamic> _materialRoute(Widget view) { return MaterialPageRoute(builder: (_) => view); } }
3. 修正Login Screen的返回逻辑
将pushReplacementNamed('/welcome')替换为Navigator.pop(context),直接弹出当前页面回到上一页:
// LoginScreen的AppBar leading点击事件 GestureDetector( onTap: () { Navigator.pop(context); // 替换原pushReplacementNamed逻辑 }, child: SvgPicture.asset( 'assets/icons/back-in-circle.svg', fit: BoxFit.contain, color: Theme.of(context).brightness == Brightness.light ? colorBlack : null, ), )
4. 可选:简化PopScope配置
如果不需要自定义返回拦截逻辑,可直接移除Login Screen中的PopScope,让系统默认处理返回行为:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( toolbarHeight: 0.09.sh, leadingWidth: 70, leading: Padding( padding: const EdgeInsets.only(left: 20), child: GestureDetector( onTap: () { Navigator.pop(context); }, child: SvgPicture.asset( 'assets/icons/back-in-circle.svg', fit: BoxFit.contain, color: Theme.of(context).brightness == Brightness.light ? colorBlack : null, ), ), )), body: SafeArea( child: Padding( padding: const EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.max, children: [ Text("Login screen") ], ), ), ), ); }
内容的提问来源于stack exchange,提问作者user13289818
相关产品推荐
相关产品推荐

