如何在Flutter中更改页面导航动画?含默认跳转/返回动画修改方法
嘿,这个问题我太熟了!Flutter里完全可以自定义页面导航的动画——不管是跳转到新页面时的入场动画,还是返回上一页的退场动画,都有好几种实用的方法,我给你一步步拆解:
这是最灵活也最常用的方式,不需要继承类,直接在跳转的时候传入自定义的PageRoute就行。比如想做一个从底部滑入/滑出的动画,代码可以这么写:
Navigator.push( context, PageRouteBuilder( // 自定义动画时长 transitionDuration: const Duration(milliseconds: 500), // 目标页面内容 pageBuilder: (context, animation, secondaryAnimation) => const NewPage(), // 核心:自定义过渡动画逻辑 transitionsBuilder: (context, animation, secondaryAnimation, child) { // 入场动画:从屏幕底部滑到顶部 const begin = Offset(0.0, 1.0); const end = Offset.zero; const curve = Curves.easeInOut; var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); // secondaryAnimation对应返回时的动画,这里直接复用反向逻辑即可 return SlideTransition( position: animation.drive(tween), child: child, ); }, ), );
要是想做淡入淡出、缩放这类动画,只需要把SlideTransition换成FadeTransition或者ScaleTransition,调整对应的Tween参数就好,上手特别快。
如果你想基于Material或者Cupertino的默认导航动画做修改(比如改滑动方向、放慢动画速度),可以直接继承MaterialPageRoute或者CupertinoPageRoute,重写buildTransitions方法:
class CustomMaterialRoute<T> extends MaterialPageRoute<T> { CustomMaterialRoute({required WidgetBuilder builder}) : super(builder: builder); @override Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { // 把默认的右滑入场改成左滑入场 const begin = Offset(-1.0, 0.0); const end = Offset.zero; var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: Curves.ease)); return SlideTransition(position: animation.drive(tween), child: child); } } // 使用时直接传这个自定义路由 Navigator.push(context, CustomMaterialRoute(builder: (context) => const NewPage()));
这种方式适合想保留默认路由的其他特性,只改动画的场景。
如果想让整个App的所有页面跳转都用同一个自定义动画,不用每个跳转都写一遍代码,可以通过MaterialApp的theme配置全局过渡主题:
MaterialApp( theme: ThemeData( pageTransitionsTheme: PageTransitionsTheme( builders: { TargetPlatform.android: CustomPageTransitionBuilder(), TargetPlatform.iOS: CustomPageTransitionBuilder(), }, ), ), home: const HomePage(), ); // 自定义全局过渡Builder class CustomPageTransitionBuilder extends PageTransitionsBuilder { @override Widget buildTransitions<T>(PageRoute<T> route, BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { // 做一个缩放+淡入的组合动画 return ScaleTransition( scale: animation.drive(Tween<double>(begin: 0.8, end: 1.0).chain(CurveTween(curve: Curves.easeOut))), child: FadeTransition( opacity: animation.drive(Tween<double>(begin: 0.0, end: 1.0)), child: child, ), ); } }
这样不管你用Navigator.push还是Navigator.pushNamed,所有页面跳转都会自动使用这个自定义动画,省了不少重复代码。
另外要注意:secondaryAnimation参数对应的就是返回上一页时的动画,如果需要单独定制返回动画的逻辑,只需要在transitionsBuilder里对这个动画做单独处理就行,比如给返回动画设置不同的曲线或者方向。
这些方法基本能覆盖大部分自定义导航动画的需求了,要是需要更复杂的组合动画(比如先缩放再滑动),也可以在transitionsBuilder里嵌套多个Transition组件,或者用AnimatedBuilder自己控制动画逻辑。
内容的提问来源于stack exchange,提问作者nlern

