利用Flutter实现“孔雀开屏”的动画效果

所属分类: 软件编程 / Android 阅读数: 79
收藏 0 赞 0 分享

前言

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

先来看下具体的效果

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

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

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

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

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

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

新的页面以圆形效果逐渐打开,注意并没有缩放效果,所以新的页面是被裁减的,新的页面以右上角为圆心,半径逐渐变大进行裁切,就是我们想要的效果。

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

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

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

class CirclePath extends CustomClipper<Path> {
 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<Path> 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<double> animation,
   Animation<double> 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,所以,不知不觉我们又学会了自定义路由。

更多精彩内容其他人还在看

Android 自定义球型水波纹带圆弧进度效果(实例代码)

最近小编接到一个这样的需求,需要实现一个圆形水波纹,带进度,两层水波纹需要渐变显示,且外围有一个圆弧进度。今天小编给大家分享实例代码,感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

Flutter 实现下拉刷新上拉加载的示例代码

这篇文章主要介绍了Flutter 实现下拉刷新上拉加载的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Windows实现Flutter环境搭建及配置这一篇就够了

这篇文章主要介绍了Windows实现Flutter环境搭建及配置这一篇就够了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Android利用碎片fragment实现底部标题栏(Github模板开源)

Fragment可以作为Activity的组成部分,一个Activity可以有多个Fragment,这篇文章主要介绍了Android利用碎片fragment实现底部标题栏(Github模板开源),需要的朋友可以参考下
收藏 0 赞 0 分享

android studio 的下拉菜单Spinner使用详解

这篇文章主要介绍了android studio 的下拉菜单Spinner使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

解析Android 8.1平台SystemUI 导航栏加载流程

这篇文章主要介绍了Android 8.1平台SystemUI 导航栏加载流程,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿微信录音功能

这篇文章主要为大家详细介绍了Android仿微信录音功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android仿微信键盘切换效果

这篇文章主要为大家详细介绍了Android仿微信键盘切换效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android超清晰6.0权限申请AndPermission

这篇文章主要介绍了Android超清晰6.0权限申请AndPermission,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android仿微信录制语音功能

这篇文章主要介绍了Android仿微信录制语音功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多