如何禁用Flutter GoRouter初始动画?解决窗口重绘动画问题
解决GoRouter初始动画重复触发的问题
核心问题分析
每次窗口大小调整触发LayoutBuilder重建时,Routes组件会重新创建新的GoRouter实例,导致每次都重新初始化路由栈,进而重复触发初始路由的过渡动画,造成视觉卡顿。
解决方案
1. 确保GoRouter实例是单例(避免重复创建)
将GoRouter实例提升为全局变量,或者在StatefulWidget的initState中初始化一次,避免每次Routes组件重建时都生成新的路由实例。
示例代码:
// 全局定义单例GoRouter及导航键 final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); final GoRouter router = GoRouter( navigatorKey: navigatorKey, initialLocation: '/', routes: [ GoRoute( path: '/', // 使用NoTransitionPage直接禁用初始路由动画 pageBuilder: (BuildContext context, GoRouterState state) { return const NoTransitionPage( child: Scaffold( body: Master(), ), ); }, ), ], ); class Routes extends StatelessWidget { const Routes({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, // 复用全局单例路由 ); } }
2. 禁用初始路由的过渡动画
通过pageBuilder返回NoTransitionPage,直接取消该路由的过渡动画效果。如果需要保留其他路由的动画,仅对初始路由使用NoTransitionPage即可。
3. 可选:自定义过渡代理(灵活控制动画)
如果需要更精细地控制路由动画(比如仅禁用初始路由动画,其他路由保留默认动画),可以自定义TransitionDelegate:
class NoInitialTransitionDelegate extends DefaultTransitionDelegate { @override Iterable<RouteTransitionRecord> resolve({ required List<RouteTransitionRecord> newPageRouteHistory, required Map<RouteTransitionRecord?, RouteTransitionRecord> locationToExitingPageRoute, required Map<RouteTransitionRecord?, List<RouteTransitionRecord>> pageRouteToPagelessRoutes, }) { // 仅当是首次初始化路由(无退出中的路由)时,跳过动画 if (newPageRouteHistory.length == 1 && locationToExitingPageRoute.isEmpty) { for (final record in newPageRouteHistory) { record.markForAdd(); } return newPageRouteHistory; } // 其他情况沿用默认过渡逻辑 return super.resolve( newPageRouteHistory: newPageRouteHistory, locationToExitingPageRoute: locationToExitingPageRoute, pageRouteToPagelessRoutes: pageRouteToPagelessRoutes, ); } }
在GoRouter中配置该代理:
final GoRouter router = GoRouter( navigatorKey: navigatorKey, initialLocation: '/', transitionDelegate: NoInitialTransitionDelegate(), routes: [ GoRoute( path: '/', builder: (context, state) => const Scaffold(body: Master()), ), // 其他路由可保留默认动画 GoRoute( path: '/detail', builder: (context, state) => const DetailPage(), ), ], );
最终调整后的App组件
无需修改App组件的LayoutBuilder逻辑,只需确保Routes复用单例GoRouter即可:
class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return Scaffold( body: const Routes(), ); }, ); } }
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

