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

Flutter GoRouter+StatefulShellBranch返回键逻辑异常求助

解决GoRouter + StatefulShellBranch返回键异常问题

核心思路

通过PopScope接管全局返回逻辑,结合StatefulNavigationShell的分支状态判断,区分首页分支与其他分支的返回行为,同时避免分支切换时误触发退出提示。

具体实现步骤

1. 记录当前活跃分支索引

在底部导航组件中,通过回调实时更新当前分支索引,确保返回逻辑能准确判断当前所处分支:

class BottomNavPage extends StatelessWidget {
  final StatefulNavigationShell navigationShell;
  final ValueChanged<int> onBranchChanged;

  const BottomNavPage({
    super.key,
    required this.navigationShell,
    required this.onBranchChanged,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: navigationShell,
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: navigationShell.currentIndex,
        onTap: (index) {
          navigationShell.goBranch(
            index,
            initialLocation: index == navigationShell.currentIndex,
          );
          // 更新当前分支索引
          onBranchChanged(index);
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: "个人中心"),
          // 另外两个分支的item
        ],
      ),
    );
  }
}

2. 用PopScope包裹全局路由,自定义返回逻辑

在StatefulShellRoute的builder中,通过PopScope拦截返回操作,根据当前分支和路由栈状态处理不同行为:

int _currentBranchIndex = 0; // 记录当前分支索引

final router = GoRouter(
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        return PopScope(
          canPop: false, // 禁用默认返回行为
          onPopInvoked: (didPop) async {
            if (didPop) return;

            // 先判断当前分支是否有子路由需要返回
            final currentNavigator = navigationShell.navigator;
            if (currentNavigator != null && currentNavigator.canPop()) {
              currentNavigator.pop();
              return;
            }

            // 无子女路由时,根据分支处理
            if (_currentBranchIndex == 0) {
              // 首页分支:弹出退出确认弹窗
              bool shouldExit = await showDialog(
                context: context,
                builder: (_) => 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 (shouldExit) SystemNavigator.pop();
            } else {
              // 其他分支:切换至首页分支
              navigationShell.goBranch(0);
            }
          },
          child: BottomNavPage(
            navigationShell: navigationShell,
            onBranchChanged: (index) => _currentBranchIndex = index,
          ),
        );
      },
      branches: [
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: "/",
              builder: (context, state) => const HomePage(),
              // 首页子路由
            ),
          ],
        ),
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: "/profile",
              builder: (context, state) => const ProfilePage(),
              // 个人中心子路由
            ),
          ],
        ),
        // 另外两个分支配置
      ],
    ),
  ],
);

关键说明

  • canPop: false:完全接管返回逻辑,避免默认的直接退出行为。
  • 子路由优先判断:确保在分支内有子页面时,先返回子页面,再处理分支级别的返回逻辑。
  • 分支切换时更新索引:保证返回逻辑能准确识别当前所处分支,不会把分支切换误判为退出操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:16:16