写点什么

flutter 系列之: 如何自定义动画路由

作者:程序那些事
  • 2023-04-19
    广东
  • 本文字数:2398 字

    阅读完需:约 8 分钟

简介

flutter 中有默认的 Route 组件,叫做 MaterialPageRoute,一般情况下我们在 flutter 中进行跳转的话,只需要向 Navigator 中传入一个 MaterialPageRoute 就可以了。


但是 MaterialPageRoute 太普通了,如果我们想要做点不同的跳转特效应该如何处理呢?


一起来看看吧。

自定义跳转使用

正常情况下,我们进行路由跳转需要用到 Navigator 和 MaterialPageRoute,如下所示:


 Navigator.push(context, MaterialPageRoute(builder: (context) {            return const NextPage();
复制代码


如果要实现特定的路由动画,那么需要进行路由的自定义。


在 flutter 中也就是要使用 PageRouteBuilder 来自定义一个 Route。


先来看下 PageRouteBuilder 的定义:


class PageRouteBuilder<T> extends PageRoute<T> {
PageRouteBuilder({ super.settings, required this.pageBuilder, this.transitionsBuilder = _defaultTransitionsBuilder, this.transitionDuration = const Duration(milliseconds: 300), this.reverseTransitionDuration = const Duration(milliseconds: 300), this.opaque = true, this.barrierDismissible = false, this.barrierColor, this.barrierLabel, this.maintainState = true, super.fullscreenDialog, })
复制代码


PageRouteBuilder 也是 PageRoute 的一种,在构建 PageRouteBuilder 的时候,通过控制不同的属性值,我们可以自由控制 pageBuilder,transitionsBuilder,transitionDuration,reverseTransitionDuration 等特性。


可以看到自由程度还是非常高的。


其中 pageBuilder 是路由将会跳转的页面,这个是必须要指定的,要不然路由也就没有意义了。


另外路由转换的效果可以经由 transitionsBuilder 来设置。


这里的 RouteTransitionsBuilder 是一个 Function,返回一个 Widget:


typedef RouteTransitionsBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child);
复制代码


所以理论上,我们可以返回任何 widget,但是一般来说,我们会返回一个 AnimatedWidget,表示一个动画效果。

flutter 动画基础

flutter 中有个专门的动画包叫做 flutter/animation.dart, flutter 中所有动画的核心叫做 Animation。


Animation 中定义了很多 listener 用来监控动画的变动情况,并且还提供了一个 AnimationStatus 来存储当前的动画状态:


abstract class Animation<T> extends Listenable implements ValueListenable<T> {  const Animation();
AnimationWithParentMixin<T>
@override void addListener(VoidCallback listener);
@override void removeListener(VoidCallback listener);
void addStatusListener(AnimationStatusListener listener);
void removeStatusListener(AnimationStatusListener listener);
AnimationStatus get status;
复制代码


AnimationStatus 是一个枚举类,它包含了现在动画的各种状态:


enum AnimationStatus {  dismissed,
forward,
reverse,
completed,}
复制代码


dismissed 表示动画暂停在开头。


forward 表示动画在从头到尾播放。


reverse 表示动画在从尾到头播放。


completed 表示动画播放完毕,停在了结尾。


有了动画的表示之后,如何对动画进行控制呢?这里就需要用到 AnimationController 了。


AnimationController 可以控制动画的 duration,动画的最低值 lowerBound 默认是 0.0,动画的最高值 upperBound 默认是 1.0 等等。


默认情况 AnimationController 中从最低值到最高值是线性变化的,如果你想设置不同的 Bound 值,那么可以尝试自定义 Animatable, 如果你想动画的变动是非线性的,那么可以尝试继承 Animation 来实现自己的变动曲线。

实现一个自定义的 route

这里我们使用 flutter 中的 SlideTransition,SlideTransition 是一个 AnimatedWidget,它表示的是一个组件的位置变化的动画。


class SlideTransition extends AnimatedWidget {  const SlideTransition({    super.key,    required Animation<Offset> position,    this.transformHitTests = true,    this.textDirection,    this.child,  }) : assert(position != null),       super(listenable: position);
复制代码


看下它的构造函数,可以看到 SlideTransition 需要一个 position 的属性,这个 position 是一个 Animation 对象,里面包含的是 Offset。


同时这个 position 是一个 listenable 对象,通过监听里面 Offset 的变化,从而重新 build 对应的 widget 从而实现动画的效果。


Offset 是一个表示位置的类,(0,0) 表示这个 widget 的左顶点在屏幕的左上角,同样的(1,1)表示这个 widget 的左顶点在屏幕的右下角。


因为 route 过后是一个新的页面,我们希望出现一个页面从右下角移动到左上角的动画,那么我们可以这样做:


Route customRoute() {  return PageRouteBuilder(    pageBuilder: (context, animation, secondaryAnimation) => const SecondPage(),    transitionsBuilder: (context, animation, secondaryAnimation, child) {      const begin = Offset(1.0, 1.0);      const end = Offset.zero;      const curve = Curves.easeOut;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition( position: animation.drive(tween), child: child, ); }, );}
复制代码


这里的 begin 和 end 表示 widget 从屏幕的右下角移动到了屏幕的左上角。


Tween 表示的是开始值和结束值之间的线性插值,是一个动态过程,另外我们还可以这个插值变动的曲线,这里使用了 CurveTween,选中了 Curves.easeOut 这种曲线类型。


最后调用 animation.drive 方法把 Tween 和 Animation 关联起来,这样一个路由动画就完成了。

总结

最后程序运行的结果如下:



其实 flutter 中的动画很简单,大家记住就是 widget 位置沿不同的曲线变化即可。


本文的例子:https://github.com/ddean2009/learn-flutter.git

发布于: 刚刚阅读数: 5
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020-06-07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:如何自定义动画路由_flutter_程序那些事_InfoQ写作社区