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

Flutter Go Router导航配置求助:启动闪屏与Shell路由需求

解决方案

一、核心问题分析

当前代码的主要问题:

  • 闪屏页未显示:用户打开任意路径时,GoRouter直接匹配对应子路由,不会触发根路径的闪屏页
  • 莫名跳转:闪屏页硬编码跳转至/catalogue,未保留用户原始访问路径
  • 导航失效:未正确使用ShellRoute,路由嵌套逻辑混乱

二、分步实现需求

1. 首次打开任意路径显示闪屏页(仅一次)

使用GoRouter的redirect功能结合状态管理,统一处理首次进入逻辑:

首先在MenuProvider中添加状态标记:

class MenuProvider extends ChangeNotifier {
  bool _hasShownSplash = false;
  String? _initialPath;

  bool get hasShownSplash => _hasShownSplash;
  String? get initialPath => _initialPath;

  void markSplashShown() {
    _hasShownSplash = true;
    notifyListeners();
  }

  void saveInitialPath(String path) {
    _initialPath = path;
    notifyListeners();
  }
}

修改GoRouter配置,添加重定向规则:

final _navigatorKey = GlobalKey<NavigatorState>();

routerConfig: GoRouter(
  navigatorKey: _navigatorKey,
  redirect: (context, state) {
    final menuProvider = Provider.of<MenuProvider>(context, listen: false);
    final currentPath = state.uri.toString();

    // 首次进入且不在闪屏页,记录原始路径并跳转至闪屏
    if (!menuProvider.hasShownSplash && currentPath != '/splash') {
      menuProvider.saveInitialPath(currentPath);
      return '/splash';
    }
    // 闪屏已显示且当前在闪屏页,跳转至原始路径(默认/catalogue)
    if (menuProvider.hasShownSplash && currentPath == '/splash') {
      return menuProvider.initialPath ?? '/catalogue';
    }
    return null; // 正常导航
  },
  routes: [
    // 闪屏页路由
    GoRoute(
      path: '/splash',
      name: 'splash',
      builder: (context, state) {
        return SplashScreenLogoV5(
          onComplete: () {
            Provider.of<MenuProvider>(context, listen: false).markSplashShown();
          },
        );
      },
    ),
    // 闪屏后启用的Shell路由
    ShellRoute(
      builder: (context, state, child) {
        // 这里是你的全局Shell布局(比如带导航栏的容器)
        return Scaffold(
          body: child,
          bottomNavigationBar: BottomNavigationBar(
            // 你的底部导航逻辑
          ),
        );
      },
      routes: [
        GoRoute(
          path: '/catalogue',
          name: 'catalogue',
          builder: (context, state) => const HomePage(),
          routes: [
            GoRoute(
              name: 'home',
              path: 'home',
              builder: (context, state) => const HomePage(),
            ),
            GoRoute(
              name: 'portfolio',
              path: 'portfolio',
              builder: (context, state) => const HomePage(startPage: 1),
            ),
            GoRoute(
              name: 'price',
              path: 'price',
              builder: (context, state) => const HomePage(startPage: 2),
            ),
            GoRoute(
              name: 'contacts',
              path: 'contacts',
              builder: (context, state) => const HomePage(startPage: 3),
            ),
          ],
        ),
      ],
    ),
  ],
),

修改闪屏页,移除硬编码跳转,改为回调通知完成:

class SplashScreenLogoV5 extends StatefulWidget {
  final VoidCallback onComplete;

  const SplashScreenLogoV5({Key? key, required this.onComplete}) : super(key: key);

  @override
  State<SplashScreenLogoV5> createState() => _SplashScreenLogoV5State();
}

class _SplashScreenLogoV5State extends State<SplashScreenLogoV5> {
  @override
  void initState() {
    super.initState();
    // 模拟闪屏时长
    Future.delayed(const Duration(seconds: 2), widget.onComplete);
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: Text('Splash Screen')),
    );
  }
}

2. 禁用浏览器返回按钮导航

在ShellRoute的布局中添加WillPopScope拦截返回事件:

ShellRoute(
  builder: (context, state, child) {
    return WillPopScope(
      onWillPop: () async {
        // 拦截Web端浏览器返回操作
        return false;
      },
      child: Scaffold(
        body: child,
        // 你的导航栏布局
      ),
    );
  },
  // ... 子路由
),

3. 优化路由状态传递

移除全局变量startPage,改为通过路由参数传递:

// HomePage接收参数
class HomePage extends StatelessWidget {
  final int startPage;

  const HomePage({Key? key, this.startPage = 0}) : super(key: key);

  // ... 页面逻辑
}

// 路由中传递参数
GoRoute(
  name: 'portfolio',
  path: 'portfolio',
  builder: (context, state) => const HomePage(startPage: 1),
),

三、额外注意事项

  • 确保detectPage()返回的主题和路由配置不会与GoRouter的内部配置冲突,建议将主题逻辑整合到Provider中管理
  • 测试时清除浏览器缓存,避免状态残留导致闪屏页不显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:30:15