美文网首页FlutterFlutter中文社区Android开发
Flutter 实现自定义页面切换转场动画

Flutter 实现自定义页面切换转场动画

作者: 岛上码农 | 来源:发表于2021-12-07 21:18 被阅读0次

    fluro 转场动画源码

    在使用自定义转场动画前,先扒一扒 fluro 的源码,通过源码可以发现这么一个标准的转场方法:

    RouteTransitionsBuilder _standardTransitionsBuilder(
          TransitionType? transitionType) {
        return (BuildContext context, Animation<double> animation,
            Animation<double> secondaryAnimation, Widget child) {
          if (transitionType == TransitionType.fadeIn) {
            return FadeTransition(opacity: animation, child: child);
          } else {
            const Offset topLeft = const Offset(0.0, 0.0);
            const Offset topRight = const Offset(1.0, 0.0);
            const Offset bottomLeft = const Offset(0.0, 1.0);
    
            Offset startOffset = bottomLeft;
            Offset endOffset = topLeft;
            if (transitionType == TransitionType.inFromLeft) {
              startOffset = const Offset(-1.0, 0.0);
              endOffset = topLeft;
            } else if (transitionType == TransitionType.inFromRight) {
              startOffset = topRight;
              endOffset = topLeft;
            } else if (transitionType == TransitionType.inFromBottom) {
              startOffset = bottomLeft;
              endOffset = topLeft;
            } else if (transitionType == TransitionType.inFromTop) {
              startOffset = Offset(0.0, -1.0);
              endOffset = topLeft;
            }
    
            return SlideTransition(
              position: Tween<Offset>(
                begin: startOffset,
                end: endOffset,
              ).animate(animation),
              child: child,
            );
          }
        };
      }
    

    从源码可以看出,根据不同枚举返回了不同的动画(即 transitionBuilder),其中TransitionType.fadeIn使用的是Flutter 自带的 FadeTransition,通过改变透明度来完成动画。而其他的左滑入、右滑入、下滑入和上滑入都是从初始偏移位置滑动到结束位置,使用的是 SlideTransition。Flutter 除了上述的 FadeTransitionSlideTransition 之外,还有如下的常用转场形式:

    • RotationTransition:旋转转场
    • ScaleTransition:缩放转场

    既然是这样,我们可以依葫芦画瓢,先用系统其他的转场效果做一个自定义的转场看看。

    旋转转场动画

    先来看看旋转的转场RotationTransition,RotationTransition 的构造方法定义如下:

    const RotationTransition({
        Key? key,
        required Animation<double> turns,
        this.alignment = Alignment.center,
        this.child,
      })  : assert(turns != null),
            super(key: key, listenable: turns);
    
    

    其中 turns 是动画控制,表示旋转的弧度数,等于动画控制值乘以2π。alignment 表示旋转围绕的中心位置,默认是居中的。旋转的弧度不要太大,否则动画过快,导致不太好看,经过验证,推荐的起始值0.2至0.3之间,结束值为0表示回到正常位置。起始值如果为负,则是顺时针;如果为正则是逆时针,示例代码如下:

    //逆时针围绕中心旋转
    RouterManager.router.navigateTo(
      context,
      RouterManager.transitionPath,
      transition: TransitionType.custom,
      transitionBuilder:
          (context, animation, secondaryAnimation, child) {
        return RotationTransition(
          turns: Tween<double>(
            begin: 0.25,
            end: 0.0,
          ).animate(animation),
          child: child,
        );
      },
    );
    
    //...
    //顺时针围绕左下角旋转
    RouterManager.router.navigateTo(
      context,
      RouterManager.transitionPath,
      transition: TransitionType.custom,
      transitionBuilder:
          (context, animation, secondaryAnimation, child) {
        return RotationTransition(
          alignment: Alignment.bottomLeft,
          turns: Tween<double>(
            begin: -0.25,
            end: 0.0,
          ).animate(animation),
          child: child,
        );
      },
    );
    

    其中 Tween 是系统自带的线性插值方法。

    缩放转场动画

    缩放转场这类在图片预览会比较常见,一般是从较小的比例缩放到1:1比例。使用方式和旋转转场类似,示例代码如下:

    RouterManager.router.navigateTo(
      context,
      RouterManager.transitionPath,
      transition: TransitionType.custom,
      transitionBuilder:
          (context, animation, secondaryAnimation, child) {
        return ScaleTransition(
          scale: Tween<double>(
            begin: 0.5,
            end: 1.0,
          ).animate(animation),
          child: child,
        );
      },
    );
    

    自定义转场动画

    通过阅读源码,其实可以发现RotationTransitionScaleTransition 都是继承自 AnimatedWidget,因此我们可以自己写一个自定义的 Transition 继承自 AnimatedWidget,在 build方法中返回一个 Transform 对象即可。通过这种方式可以做自定义的转场动画效果。我们以变形为例,可以利用 Matrix4skew 方法,在 x 和 y 轴进行变形,就可以得到转场类似卡片变形的效果。也可以只在 X 轴或 Y 轴变形(skewXskewY 方法)。这里以 x,y 轴同时变形定义了一个转场动画:

    class SkewTransition extends AnimatedWidget {
      const SkewTransition({
        Key key,
        Animation<double> turns,
        this.alignment = Alignment.center,
        this.child,
      })  : assert(turns != null),
            super(key: key, listenable: turns);
    
      Animation<double> get turns => listenable as Animation<double>;
    
      final Alignment alignment;
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        final double turnsValue = turns.value;
        final Matrix4 transform =
            Matrix4.skew(turnsValue * pi * 2.0, turnsValue * pi * 2.0);
        return Transform(
          transform: transform,
          alignment: alignment,
          child: child,
        );
      }
    }
    

    使用方式和 RotationTransition 类似:

    RouterManager.router.navigateTo(
      context,
      RouterManager.transitionPath,
      transition: TransitionType.custom,
      transitionBuilder:
          (context, animation, secondaryAnimation, child) {
        return SkewTransition(
          turns: Tween<double>(
            begin: -0.05,
            end: 0.0,
          ).animate(animation),
          child: child,
        );
      },
    );
    

    实际也可以尝试使用围绕 X 轴旋转,围绕 Y 轴旋转,以及变更中心点位置(alignment)来实现不同的动画转场效果。如果需要更为复杂的动画效果,则可以研究动画的实现,后续篇章将有对应动画的介绍。

    运行效果

    运行效果如下图所示:

    自定义转场动效

    总结

    本篇介绍了 fluro 导航到其他页面的自定义转场动画实现,Flutter本身提供了不少预定义的转场动画,可以通过 transitionBuilder 参数设计多种多样的转场动画,也可以通过自定义的 AnimatedWidget实现个性化的转场动画效果。

    相关文章

      网友评论

        本文标题:Flutter 实现自定义页面切换转场动画

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