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

3次阅读

共计 3488 个字符,预计需要花费 9 分钟才能阅读完成。

简介

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

正文完
 0