
GoRouter 页面转场动画完全指南用 CustomTransitionPage 为每条 GoRoute 定制过渡效果【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packagesGoRouter 是 Flutter 官方团队维护的声明式路由库本指南基于其官方文档 transition-animations.md讲解如何为每个GoRoute定制专属的转场动画。通过本文你将掌握pageBuilder与CustomTransitionPage的完整用法、transitionsBuilder的动画原理、全部可配置参数的含义并看到可运行的仓库示例与测试验证从而在项目里实现淡入淡出、缩放、滑动、对话框遮罩等任意自定义转场效果。一、为什么需要自定义转场动画默认情况下GoRouter 会按照平台惯例为页面切换使用内置动画在 Material 应用中生成MaterialPage在 Cupertino 应用中生成CupertinoPage对应实现见 pages/material.dart 与 pages/cupertino.dart。这些默认转场开箱即用但存在两个局限全局统一默认转场对所有路由一视同仁无法为某个特殊页面如详情页、模态框、引导页单独设计入场效果不可定制动画曲线、时长、遮罩行为均无法按路由调整。CustomTransitionPage正是为打破这两个局限而生。从源码看它的定位非常明确见 custom_transition_page.dartPage with custom transition functionality. To be used instead of MaterialPage or CupertinoPage, which provide their own transitions.也就是说只要你在路由的pageBuilder中返回CustomTransitionPage该页面就会完全绕开平台的默认转场转由你提供的transitionsBuilder决定进出场动画。二、核心概念pageBuilder 与 CustomTransitionPage1. pageBuilder 是定制转场的入口GoRoute提供两种页面构建方式builder返回一个普通的WidgetGoRouter 内部会将其包装成平台默认的MaterialPage/CupertinoPagepageBuilder返回一个PageObject?对象你可以完全掌控页面类型因此它是自定义转场的唯一入口。两者的取舍在 builder.dart 中有明确体现_buildPageForGoRoute会优先使用pageBuilder只有当它不存在时才回退到builder并用平台适配器包装。从 route.dart 还可以看到 GoRoute 的构造函数断言builder、pageBuilder、redirect三者至少提供一个且若提供了onExit则必须同时有builder或pageBuilder。这意味着「自定义转场」和「离开拦截回调」可以组合使用。2. CustomTransitionPage 的官方示例原文档给出了最基础、也最具代表性的淡入淡出Fade转场示例这是定制转场的「标准骨架」GoRoute( path: details, pageBuilder: (context, state) { return CustomTransitionPage( key: state.pageKey, child: DetailsScreen(), transitionsBuilder: (context, animation, secondaryAnimation, child) { // 基于动画值使用曲线改变页面的透明度 return FadeTransition( opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation), child: child, ); }, ); }, ),这段代码有三个关键点需要理解key: state.pageKey每个路由状态都有唯一的pageKey必须把它传给CustomTransitionPage保证页面在路由重建、深链跳转时状态一致transitionsBuilder的四个参数context构建上下文、animation本路由的主动画push 时从 0→1pop 时从 1→0、secondaryAnimation被压在下方的路由动画用于实现上层切换时下层同步缩放/平移等联动效果、child页面本体必须原样返回或包裹曲线动画组合CurveTween(curve: ...).animate(animation)是 Flutter 中给动画套用缓动曲线的标准写法这里选用了Curves.easeInOutCirc让淡入淡出带有先慢后快再慢的韵律感。3. 仓库示例三种转场形态一网打尽原文档提到的完整示例位于仓库的 example/lib/transition_animations.dart。它在/根路由下嵌套了三个子路由分别演示了三种典型的自定义转场场景非常值得逐段研读。场景一标准淡入淡出duration 150msGoRoute( path: details, pageBuilder: (BuildContext context, GoRouterState state) { return CustomTransitionPagevoid( key: state.pageKey, child: const DetailsScreen(), transitionDuration: const Duration(milliseconds: 150), transitionsBuilder: ( BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation, Widget child, ) { return FadeTransition( opacity: CurveTween(curve: Curves.easeInOut).animate(animation), child: child, ); }, ); }, ),与文档版相比示例补充了transitionDuration入场时长 150ms并把曲线换成了更通用的Curves.easeInOut。场景二可点击遮罩关闭的对话框页面GoRoute( path: dismissible-details, pageBuilder: (BuildContext context, GoRouterState state) { return CustomTransitionPagevoid( key: state.pageKey, child: const DismissibleDetails(), barrierDismissible: true, // 点击遮罩可关闭 barrierColor: Colors.black38, // 半透明黑色遮罩 opaque: false, // 不遮挡下层路由 transitionDuration: Duration.zero, transitionsBuilder: (_, _, _, Widget child) child, // 无转场瞬开 ); }, ),这一场景展示了用CustomTransitionPage模拟模态对话框的完整套路barrierDismissible: true让用户点击页面外的遮罩即可返回opaque: false表示该页面不透明地覆盖下层——从 custom_transition_page.dart 的注释可知不透明路由在入场完成后下层路由将不再被构建以节省资源而透明路由则始终保留下层渲染这正是对话框场景所需要的。transitionDuration: Duration.zero配合恒等transitionsBuilder实现瞬间弹出。场景三正反转场时长不对称GoRoute( path: custom-reverse-transition-duration, pageBuilder: (BuildContext context, GoRouterState state) { return CustomTransitionPagevoid( key: state.pageKey, child: const DetailsScreen(), barrierDismissible: true, barrierColor: Colors.black38, opaque: false, transitionDuration: const Duration(milliseconds: 500), // 入场 500ms reverseTransitionDuration: const Duration(milliseconds: 200), // 退场 200ms transitionsBuilder: ( BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation, Widget child, ) { return FadeTransition(opacity: animation, child: child); }, ); }, ),入场慢、退场快的快进快出效果可以让模态页的关闭响应更跟手。整个示例通过context.go(/details)等命令式 API 驱动跳转见 transition_animations.dart导航按钮都定义在HomeScreen中读者可直接运行go_router/example目录下的示例应用逐一点击体验。三、transitionsBuilder 参数与动画机制详解transitionsBuilder的类型签名是Widget Function( BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation, Widget child, )它在 custom_transition_page.dart 中被定义。源码注释揭示了它的调用时机与语义理解这些对写出正确动画至关重要调用时机每当路由在可见状态下状态发生变化例如当前路由的canPop值改变时transitionsBuilder都会被重新调用animation的驱动方向当 Navigator 把新路由压入栈顶时主动画从0.0运行到1.0入场当用户按返回键弹出栈顶路由时主动画从1.0运行到0.0退场。因此动画是否反转完全由导航方向决定你在 builder 里只需面向animation的值编写映射即可secondaryAnimation的作用它代表栈中下一层路由的动画常被用来实现上层页面切换时下层页面轻微缩放/位移的沉浸式效果child的职责child是路由的真实内容由buildPage返回它被 Semantics 包裹以保证无障碍语义scopesRoute: true你的transitionsBuilder必须原样返回它或用各种过渡组件把它包起来。从 builder.dart 的调用链可以确认pageBuilder返回的Page对象最终会交给_CustomTransitionPageRoute继承自 Flutter 的PageRoutetransitionDuration、reverseTransitionDuration、barrierDismissible、barrierColor、barrierLabel、maintainState、fullscreenDialog、opaque等参数会被逐一透传到PageRoute的对应 getter见 custom_transition_page.dart从而真正影响导航行为——这保证了你在配置里写的每个参数都不是摆设。四、CustomTransitionPage 全部可配置参数以下参数全部来自 CustomTransitionPage 构造函数结合源码注释整理其含义与默认值参数类型默认值作用childWidget必填—路由展示的内容即你的页面 WidgettransitionsBuilder函数必填—定义页面进场/退场动画的构建函数transitionDurationDuration300ms入场动画时长reverseTransitionDurationDuration300ms退场pop动画时长maintainStatebooltrue路由进入非激活状态时是否保留内存中的 widget 树若设为false框架会完全丢弃不可见路由的子树以省资源但需注意被压住的路由持有的 Future 在下一路由弹出时可能无法正常 resolvefullscreenDialogboolfalse是否为全屏对话框Material/Cupertino 中会令 AppBar 显示关闭按钮而非返回按钮iOS 上对话框转场方式不同且不能用返回滑动手势关闭opaquebooltrue转场完成后该路由是否遮住下层路由true时下层路由停止构建以省资源barrierDismissibleboolfalse是否可通过点击模态遮罩关闭本路由barrierColorColor?null透明模态遮罩颜色barrierLabelString?null遮罩的无障碍语义标签当遮罩可点击时VoiceOver 等读屏工具聚焦遮罩会朗读该文本key/name/arguments/restorationId——继承自 FlutterPage的基础属性其中key务必传入state.pageKey实际项目中对话框 遮罩 自定义动画是最常见的组合官方测试 custom_transition_page_test.dart 演示了完整用法GoRoute( path: /dismissible-modal, pageBuilder: (_, GoRouterState state) CustomTransitionPagevoid( key: state.pageKey, barrierDismissible: true, transitionsBuilder: (_, _, _, Widget child) child, child: const DismissibleModal(key: dismissibleModalKey), ), ),测试通过router.push(/dismissible-modal)打开页面再tester.tapAt(const Offset(50, 50))点击左上角遮罩区域验证页面被成功关闭——这正是barrierDismissible生效的直接证据。五、进阶常用转场效果模板理解了transitionsBuilder的机制后可以自由组合 Flutter 内置的动画组件实现各类效果。以下模板可直接套用以本仓库示例为基底扩展滑动进入SlidetransitionsBuilder: (context, animation, secondaryAnimation, child) { final offset TweenOffset( begin: const Offset(1, 0), // 从右侧滑入 end: Offset.zero, ).animate(CurvedAnimation(parent: animation, curve: Curves.easeOutCubic)); return SlideTransition(position: offset, child: child); },缩放进入ScaletransitionsBuilder: (context, animation, secondaryAnimation, child) { return ScaleTransition( scale: Tweendouble(begin: 0.8, end: 1.0).animate(animation), child: FadeTransition(opacity: animation, child: child), ); },双层联动利用 secondaryAnimationtransitionsBuilder: (context, animation, secondaryAnimation, child) { // 下层页面随上层入场轻微缩小形成视觉层级感 return ScaleTransition( scale: Tweendouble(begin: 1.0, end: 0.95).animate(secondaryAnimation), child: child, ); },完全禁用转场瞬切GoRouter 内置了NoTransitionPage它在 custom_transition_page.dart 中定义为transitionDuration与reverseTransitionDuration均为Duration.zero、transitionsBuilder恒等返回child的CustomTransitionPage子类适合引导页、登录页等不希望有动画干扰的场景GoRoute( path: login, pageBuilder: (context, state) NoTransitionPage(key: state.pageKey, child: const LoginScreen()), ),官方测试 custom_transition_page_test.dart 专门验证了NoTransitionPage在 push 与 pop 两个方向都不产生任何过渡动画。六、测试验证转场动画的可测性GoRouter 的转场配置有完整的测试支撑这保证了自定义转场在生产环境中可被自动化验证示例级冒烟测试example/test/transition_animations_test.dart 启动示例 App依次点击Go to the Details screen→Go back to the Home screen用pumpAndSettle()等待动画结束并断言页面正确切换——验证了CustomTransitionPage示例的端到端可用性单元级行为测试test/custom_transition_page_test.dart 覆盖四种行为——transitionsBuilder被正确调用并构建 child、NoTransitionPage双向无动画、点击遮罩关闭路由、正反转场时长不同通过对比 push 与 pop 的pumpAndSettle()次数来断言transitionDuration与reverseTransitionDuration确实生效。如果你在自己的项目中引入CustomTransitionPage可以仿照上述测试编写testWidgets用例使用pumpAndSettle()推进动画帧用find.byType(FadeTransition)等 finder 断言转场组件是否出现在 widget 树中。七、总结GoRouter 的自定义转场能力可以概括为一条主线GoRoute.pageBuilder是开关CustomTransitionPage是载体transitionsBuilder是动画灵魂。官方文档 transition-animations.md 给出的淡入淡出示例虽短却完整包含了pageKey、曲线动画组合、四参数 builder 签名等全部核心要素而仓库中的 transition_animations.dart 示例与 custom_transition_page.dart 源码则进一步揭示了参数默认值、底层PageRoute透传机制与NoTransitionPage等进阶用法。掌握这套机制后你可以在不引入任何第三方动画库的前提下为应用中的每个页面打造独一无二、贴合产品气质的转场体验。【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考