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

作者:老孟 时间:2021-11-04 21:24:17 

前言

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

先来看下具体的效果

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

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

在使用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,所以,不知不觉我们又学会了自定义路由。

来源:https://segmentfault.com/a/1190000022730934

标签:flutter,动画,开屏
0
投稿

猜你喜欢

  • Java数据结构 递归之迷宫回溯案例讲解

    2023-04-01 11:16:38
  • java高并发的线程中断的几种方式详解

    2022-08-25 01:35:09
  • C#域名解析简单实现方法

    2023-08-26 15:30:55
  • SpringBoot Jpa分页查询配置方式解析

    2023-03-02 10:04:02
  • Java日常练习题,每天进步一点点(55)

    2022-10-13 15:51:03
  • 详解java爬虫jsoup解析多空格class数据

    2021-12-30 14:47:41
  • java8 forEach结合Lambda表达式遍历 List操作

    2021-07-04 07:22:55
  • C#数据类型实现背包、队列和栈

    2022-10-07 06:42:09
  • SpringBoot整合MybatisPlus实现增删改查功能

    2022-10-31 05:24:15
  • SpringBoot基于Sentinel在服务上实现接口限流

    2023-11-27 17:19:25
  • 基于SPRINGBOOT配置文件占位符过程解析

    2021-06-27 04:25:12
  • Java IO流相关知识代码解析

    2023-08-05 05:48:04
  • Spring Native项目实战(体验79毫秒启动springboot应用)

    2022-03-14 22:18:42
  • c#测试反射性能示例

    2021-12-19 23:13:47
  • Android开发之保存图片到相册的三种方法详解

    2022-07-26 04:49:10
  • Android自定义状态栏颜色与应用标题栏颜色一致

    2022-01-12 02:24:31
  • 使用java从乱码文本中解析出正确的文本

    2023-12-03 12:10:22
  • Java之int和string类型转换详解

    2023-11-06 04:10:06
  • 详解java中BigDecimal精度问题

    2021-08-17 10:24:59
  • 基于spring AOP @Around @Before @After的区别说明

    2023-12-15 03:08:25
  • asp之家 软件编程 m.aspxhome.com