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

如何禁用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:27:38