美文网首页Flutter 入门与实战
Flutter 自定义 Hero 动画的路径

Flutter 自定义 Hero 动画的路径

作者: 岛上码农 | 来源:发表于2022-06-11 12:44 被阅读0次

    前言

    我们在 页面切换转场动画,英雄救场更有趣!介绍了 Hero 动画效果,使用 Hero 用于转场能够提供非常不错的体验。既然称之为英雄,肯定还有其他技能,本篇我们就来探索一下 Hero 动画的返回效果。

    Hero 的定义

    Hero 组件是一个 StatefulWidget,构造方法如下:

    const Hero({
      Key? key,
      required this.tag,
      this.createRectTween,
      this.flightShuttleBuilder,
      this.placeholderBuilder,
      this.transitionOnUserGestures = false,
      required this.child,
    })
    

    其中 createRectTween 就是一个矩形插值,用于控制 Hero 组件的路径。实际上,和普通动画一样,也是有一个时间曲线,取值范围是0-1.0,然后createRectTween保证 Hero 组件动画前后能够达到矩形指定位置和大小。下面一张图是官网的说明图:

    动画路径

    RectTween

    RectTween 和 Tween<double>类似,实际上就是矩阵在动画过程中的变化。我们来看 RectTween 的定义:

    class RectTween extends Tween<Rect?> {
      RectTween({ Rect? begin, Rect? end }) : super(begin: begin, end: end);
    
      /// 通过给定的动画时间值构建新的插值矩形
      @override
      Rect? lerp(double t) => Rect.lerp(begin, end, t);
    }
    

    这个类很简单,其实就是每次动画时间点上调用 Rect.lerp 构建一个插值的矩形。Rect.lerp 方法如下:

    static Rect? lerp(Rect? a, Rect? b, double t) {
        assert(t != null);
        if (b == null) {
          if (a == null) {
            return null;
          } else {
            final double k = 1.0 - t;
            return Rect.fromLTRB(a.left * k, a.top * k, a.right * k, a.bottom * k);
          }
        } else {
          if (a == null) {
            return Rect.fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
          } else {
            return Rect.fromLTRB(
              _lerpDouble(a.left, b.left, t),
              _lerpDouble(a.top, b.top, t),
              _lerpDouble(a.right, b.right, t),
              _lerpDouble(a.bottom, b.bottom, t),
            );
          }
        }
      }
    

    在矩形 a 和矩形 b 都不为空的时候,返回的就是一个通过定点定义的新的矩形。这里的关键是_lerpDouble 方法,其实最终就是根据动画时间完成顶点的移动。

    double? lerpDouble(num? a, num? b, double t) {
      /// ...
      return a * (1.0 - t) + b * t;
    }
    

    也就是从矩形 a 的顶点逐步移动到矩形 b的顶点,从而完成了两个矩形的动画过渡。有了这个基础我们就可以构建自定义的 RectTween 了。和我们的之前说过的动画曲线(动画曲线天天用,你能自己整一个吗?看完这篇你就会了!)是类似的。

    自定义RectTween

    我们来一个自定义 RectTween,然后保证起始点是矩形 a,结束点是矩形 b,然后中间沿曲线变动就可以了。下面是我们利用曲线将时间转换后得到的一个自定义 RectTween。其中使用曲线转换后的transformT取值还是从0-1.0,然后使用_rectMove 方法就能实现从开始的矩形过渡到结束的矩形了。

    class CustomRectTween extends RectTween {
      final Rect begin;
      final Rect end;
    
      CustomRectTween({required this.begin, required this.end})
          : super(begin: begin, end: end);
    
      @override
      Rect lerp(double t) {
        double transformT = Curves.easeInOutBack.transform(t);
    
        var rect = Rect.fromLTRB(
            _rectMove(begin.left, end.left, transformT),
            _rectMove(begin.top, end.top, transformT),
            _rectMove(end.right, end.right, transformT),
            _rectMove(begin.bottom, end.bottom, transformT));
    
        return rect;
      }
    
      double _rectMove(double begin, double end, double t) {
        return begin * (1 - t) + end * t;
      }
    }
    

    运行效果

    可以看到结束的时候,有个回弹效果,那是因为使用了Curves.easeInOutBack 这个曲线。源码已上传至:动画相关源码

    运行效果

    总结

    本篇介绍了 Hero 动画组件的 createRectTween 属性实现自定义路径效果的动画。实际使用的时候,可以根据自己需要构建一些有趣的路径提升用户体验或增加趣味性。

    相关文章

      网友评论

        本文标题:Flutter 自定义 Hero 动画的路径

        本文链接:https://www.haomeiwen.com/subject/vonimrtx.html