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

使用GoRouter时无法实现App退出前的确认弹窗问题

解决GoRouter下HomePage返回键无确认弹窗问题

问题根源

GoRouter接管了Flutter的导航事件流,普通WillPopScope(已废弃)无法拦截根页面的系统返回操作,这是你之前尝试无效的核心原因。推荐使用Flutter 3.12+推出的PopScope组件,或通过GoRouter自身的导航钩子来实现需求。

方案一:使用PopScope(推荐)

直接在HomePage中用PopScope包裹整个Scaffold,拦截返回事件并弹出确认框:

import 'package:flutter/services.dart';

@override
Widget build(BuildContext context) {
  return PopScope(
    // 阻止默认返回行为,交由自定义逻辑处理
    canPop: false,
    onPopInvoked: (bool didPop) async {
      if (didPop) return;
      
      final shouldExit = await showDialog<bool>(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('确认退出'),
          content: const Text('确定要退出应用吗?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(false),
              child: const Text('取消'),
            ),
            TextButton(
              onPressed: () {
                Navigator.of(context).pop(true);
                // 调用系统API退出应用
                SystemNavigator.pop();
              },
              child: const Text('确定'),
            ),
          ],
        ),
      );
    },
    child: Scaffold(
      key: HomePage.scaffoldKey,
      drawer: DrawerWithDropdown(),
      backgroundColor: tdWhite,
      body: const SafeArea(
        // 你的页面内容
      ),
    ),
  );
}

方案二:通过GoRouter全局拦截

如果你需要全局统一处理返回逻辑,可以自定义GoRouter的onPopPage方法:

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

final router = GoRouter(
  navigatorKey: navigatorKey,
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
    ),
    // 其他路由配置
  ],
  onPopPage: (route, result) async {
    // 判断是否为根页面的返回操作
    if (route.settings.name == '/' && result == null) {
      final shouldExit = await showDialog<bool>(
        context: navigatorKey.currentContext!,
        builder: (context) => AlertDialog(
          title: const Text('确认退出'),
          content: const Text('确定要退出应用吗?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(false),
              child: const Text('取消'),
            ),
            TextButton(
              onPressed: () => Navigator.of(context).pop(true),
              child: const Text('确定'),
            ),
          ],
        ),
      );

      if (shouldExit == true) {
        SystemNavigator.pop();
        return false; // 阻止路由栈pop,直接退出应用
      } else {
        return false; // 取消退出,拦截返回动作
      }
    }
    return route.didPop(result);
  },
);

关键注意点

  • 避免将拦截组件嵌套在Scaffold的body内,需包裹整个页面组件
  • 退出应用必须调用SystemNavigator.pop(),而非仅通过Navigator操作路由栈
  • 若使用旧版Flutter(<3.12),可替换为WillPopScope并包裹Scaffold,但优先推荐PopScope

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:11:12