Flutter:如何实现启动页自动跳转至下一页面?
你的代码里有几个导致启动页无法正常显示并跳转的问题:
- 根路由
/同时设置了builder(返回SplashScreen)和redirect,GoRouter的redirect会优先执行,导致SplashScreen还没显示就被跳转走了。 - 子路由的path写法错误:子路由的path不应该以
/开头,比如/login应该改成login,否则会被识别为绝对路径,和父路由的路径拼接出错。 - BlocProvider中创建的AuthBloc和传给goRouter的authBloc不是同一个实例,导致状态监听和token检查可能不一致。
以下是修正后的实现方案:
1. 调整路由结构,分离启动页与其他路由
把SplashScreen作为单独的根路由,login、homepage设置为同级路由,避免redirect直接跳过启动页:
GoRouter goRouter(AuthBloc authBloc) { return GoRouter( navigatorKey: GlobalKey<NavigatorState>(), initialLocation: '/', routes: <GoRoute>[ // 启动页路由 GoRoute( path: '/', name: 'splash', builder: (context, state) => const SplashScreen(), ), // 登录页路由 GoRoute( path: '/login', name: 'login', builder: (context, state) => const LoginPage(), ), // 主页路由 GoRoute( path: '/homepage', name: 'homepage', builder: (context, state) { return BlocProvider<WeatherBloc>( create: (context) => WeatherBloc(), child: MyHomepage(dateTime: DateTime.now()), ); }, routes: [ // 子路由去掉开头的/ GoRoute( path: 'gempa', name: 'gempa', builder: (context, state) { return BlocProvider<GempaBloc>( create: (context) => GempaBloc(), child: const GempaPage(), ); }, ), ], ), ], ); }
2. 统一AuthBloc实例,在启动页中处理跳转逻辑
确保MyApp中使用同一个AuthBloc实例,然后在SplashScreen内部监听状态变化完成跳转:
class _MyAppState extends State<MyApp> { final FirebaseAuthService firebaseAuthService = FirebaseAuthService(); late final AuthBloc authBloc; @override void initState() { super.initState(); authBloc = AuthBloc(firebaseAuthService)..add(CheckSignStatus()); } @override Widget build(BuildContext context) { return BlocProvider.value( value: authBloc, child: MaterialApp.router( title: 'sample', routerConfig: goRouter(authBloc), debugShowCheckedModeBanner: false, theme: ThemeData( textTheme: GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme), ), ), ); } }
编写SplashScreen,在内部监听AuthBloc状态实现跳转:
class SplashScreen extends StatelessWidget { const SplashScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocListener<AuthBloc, AuthState>( listener: (context, state) { if (state is AuthUser) { // go方法等效于pushReplacement,替换当前栈顶路由 context.go('/homepage'); // 若需完全清除栈可使用replace:context.replace('/homepage'); } else if (state is NonAuthUser) { context.go('/login'); // 若需完全清除栈可使用replace:context.replace('/login'); } }, child: const Scaffold( body: Center( child: Text('启动页...'), ), ), ); } }
补充说明
- GoRouter的
context.go()默认替换当前栈顶路由,效果和pushReplacement一致;如果需要清空整个路由栈再跳转,可使用context.replace()。 - 移除了原根路由的redirect逻辑,改为在SplashScreen中监听状态跳转,确保启动页先显示再执行跳转。
- 修正了子路由的path写法,子路由path无需以
/开头,否则会被解析为绝对路径导致匹配错误。
内容的提问来源于stack exchange,提问作者Babay
相关产品推荐
相关产品推荐

