android动画矩形边框闪动_Flutter“孔雀开屏”的动画效果

  • Post author:
  • Post category:其他


d76536a1496bfa6e1d561f1afbd16839.png

老孟导读:今天分享一个类似“孔雀开屏”的动画效果,打开新的页面时,新的页面从屏幕右上角以圆形逐渐打开到全屏。

先来看下具体的效果

ebeb58026e9ea55184b2d96f95db12f7.gif

不知道这种效果大家叫什么名字?如果有更合适的名字可以在评论处告诉我,下面来说下如何实现此效果。

在使用Navigator进入一个新的页面时,通常用法如下:

Navigator.of(context).push(MaterialPageRoute(  builder: (context){    return PageB();  }));

MaterialPageRoute就包含了切换页面时的动画效果,在iOS上效果是左右滑动切换,在Android上效果是上下滑动,如果想要自定义切换效果如何实现呢?答案是使用PageRouteBuilder,用法如下:

Navigator.of(context).push(PageRouteBuilder(pageBuilder:    (BuildContext context, Animation animation,        Animation secondaryAnimation) {  ...}));

在pageBuilder函数中使用animation返回新页面的动画效果即可。

新的页面以

圆形

效果逐渐打开,注意并没有缩放效果,所以新的页面是被

裁减

的,新的页面以右上角为圆心,半径逐渐变大进行裁切,就是我们想要的效果。

通过上面的分析,使用ClipPath对新的页面进行裁切

Navigator.of(context).push(PageRouteBuilder(pageBuilder:    (BuildContext context, Animation animation,        Animation secondaryAnimation) {  return AnimatedBuilder(    animation: animation,    builder: (context, child) {      return ClipPath(        clipper: CirclePath(animation.value),        child: child,      );    },    child: PageB(),  );}));

重点是CirclePath,这就是裁切的路径,

class CirclePath extends CustomClipper {  CirclePath(this.value);  final double value;  @override  Path getClip(Size size) {    var path = Path();    double radius =        value * sqrt(size.height * size.height + size.width * size.width);    path.addOval(Rect.fromLTRB(        size.width - radius, -radius, size.width + radius, radius));    return path;  }  @override  bool shouldReclip(CustomClipper oldClipper) {    return true;  }}

由于Path没有直接添加圆形的API函数,因此使用

椭圆

方法,只需将

椭圆

的矩形区域设置为正方形,那么裁切出来的就是圆形。

半径的最大值并不是屏幕的宽或者高,而是屏幕的对角线长度。

由于是从右上角开始,而且裁切的矩形区域必须是正方形,所以裁切的矩形区域是超出页面区域的。

如果很多页面都用到了这个效果,可以进行封装,类似于MaterialPageRoute,封装如下:

class CirclePageRoute extends PageRoute {  CirclePageRoute({    @required this.builder,    this.transitionDuration = const Duration(milliseconds: 500),    this.opaque = true,    this.barrierDismissible = false,    this.barrierColor,    this.barrierLabel,    this.maintainState = true,  });  final WidgetBuilder builder;  @override  final Duration transitionDuration;  @override  final bool opaque;  @override  final bool barrierDismissible;  @override  final Color barrierColor;  @override  final String barrierLabel;  @override  final bool maintainState;  @override  Widget buildPage(BuildContext context, Animation animation,      Animation secondaryAnimation) {    return AnimatedBuilder(      animation: animation,      builder: (context, child) {        return ClipPath(          clipper: CirclePath(animation.value),          child: child,        );      },      child: builder(context),    );  }}

使用

Navigator.of(context).push(CirclePageRoute(builder: (context) {  return PageB();}));

如果你查看CupertinoPageRoute、MaterialPageRoute、PageRouteBuilder的源码,你会发现这3个都是继承自PageRoute,所以,不知不觉我们又学会了自定义路由。

交流

老孟Flutter博客地址(近200个控件用法):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】



版权声明:本文为weixin_31433527原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。