利用Flutter绘制出3D效果动画

目录
  • 前言
  • Path 的 transform 方法
  • 绕任意点旋转
  • 卡片3D 旋转实现
  • 日历翻页效果
  • 总结

前言

本篇我们继续介绍 Flutter 绘图的 Path 的应用。Flutter 的 Path 类提供了一个三维空间的变换方法,可以实现路径在三维空间的平移、旋转等操作,从而可以实现3D 绘制的效果。通过本篇你将了解到:

  • Path的三维转换方法 transform 的使用。
  • 绕三维空间某一点的旋转实现。
  • 卡片3D 旋转动效。
  • 类似日历的三维翻页效果。

Path 的 transform 方法

Path 类的 transform 方法 将给定的Path 通过一个Float64List的对象进行三维变换,然后返回变换后的 Path对象,方法定义如下。

Path transform(Float64List matrix4) {
  assert(_matrix4IsValid(matrix4));
  final Path path = Path._();
  _transform(path, matrix4);
  return path;
}

其中 Float64List 一般都是通过 Matrix4 对象的 storage得到,例如我们在 x 方向平移5.0,可以按如下方式得到对应的 Float64List 对象。

var transform = (Matrix4.identity()
  ..translate(5.0, 0.0, 0.0)).storage;

Matrix4提供了平移、旋转、逆矩阵等多种方法,有兴趣的可以看一下 Matrix4的源码,实际上就是大学线性代数课(这门课还挺难的)的矩阵乘法内容。

绕任意点旋转

网上关于绕任意点的旋转推导很多,这里就不再赘述,结论就是实际上三个矩阵,先按给定点的(x,y,z)平移,再按给定的角度旋转,再按给定点的反向(-x,-y,-z)平移。比如下面是围绕 point 点,在 X 轴方向旋转 angle 角度的变换代码。

var transform = Matrix4.identity()
  ..translate(point.dx, point.dy, point.dz)
  ..rotateX(angle)
  ..translate(-point.dx, -point.dy, -point.dz);

卡片3D 旋转实现

有了上面的基础,我们就可以实现卡片的3D旋转效果了。

这个实际就是用 Path 绘制了一个实心的正方形,然后绕中心点同时在 X 轴和 Y 轴旋转,旋转的角度由动画来控制。然后在动画值的中间的变更颜色,就看起来像是两面了。具体实现的代码如下。

var paint = Paint()
  ..style = PaintingStyle.fill
  ..color = Colors.blue[400]!
  ..strokeWidth = 4.0;

var center = Offset(size.width / 2, size.height / 2);
var path = Path();
final rectSize = 100.0;
path.addRect(Rect.fromCenter(
    center: Offset(center.dx, center.dy),
    width: rectSize,
    height: rectSize));
var transform = Matrix4.identity()
  ..translate(center.dx, center.dy, 0.0)
  ..rotateX(pi * animationValue)
  ..rotateY(pi * animationValue)
  ..translate(-center.dx, -center.dy, 0.0);

var transformedPath = path.transform(transform.storage);
if (animationValue < 0.5) {
  paint.color = Colors.blue[400]!;
} else {
  paint.color = Colors.red;
}
canvas.drawPath(transformedPath, paint);

我们还可以绕 Z 轴旋转来看看效果。

日历翻页效果

老的日历通常是挂在墙上,过了一天就把这一天的翻上去。

观察上面的图,下面的部分是矩形,上面翻上去的会有一个曲度,这个我们可以通过贝塞尔曲线来实现。然后,翻页过程其实就是从下面绕中间位置旋转岛上面的过程,只是在旋转过程中需要同时更改绘制的路径,逐步从矩形过渡到带有曲度的形状。

下半部分绘制

下半部分绘制比较简单,我们为了体现日历的厚度,可以绘制多个高度错开的矩形,并且颜色有点偏差,看起来就像有厚度了。

绘制代码如下,这里有两个关键点,一个是每次绘制的矩形会往下偏和往右偏移一定的位置,另一个是更改绘制颜色的透明度,这样就会有厚度的感觉了。

var bottomPath = Path();
for (var i = 0; i < 10; ++i) {
  bottomPath.addRect(Rect.fromCenter(
      center: Offset(
          size.width / 2 + i / 1.5, center.dy + rectSize / 2 + i * 1.5),
      width: rectSize,
      height: rectSize));
  paint.color = Colors.white70.withAlpha(240 + 10 * i);
  canvas.drawPath(bottomPath, paint);

上半部分的绘制

上半部分我们的侧边绘制一定的曲度,这样看着像翻过后卷起来的感觉。因为有部分卷起来了,因此高度会比下半部分低一些,曲度我们通过贝塞尔曲线控制,绘制的代码如下,这里有两个常量,一个是 topHeight 代表上半部分的高度,一个是 flippedSize,用于控制贝塞尔曲线的曲度。

final topHeight = 90.0;
final flippedSize = -10.0;

var topPath = Path();
topPath.moveTo(center.dx - rectSize / 2, center.dy);
topPath.lineTo(center.dx + rectSize / 2, center.dy);
topPath.quadraticBezierTo(
    center.dx + rectSize / 2 + flippedSize,
    center.dy - topHeight / 2,
    center.dx + rectSize / 2,
    center.dy - topHeight);
topPath.lineTo(center.dx - rectSize / 2, center.dy - topHeight);
topPath.quadraticBezierTo(center.dx - rectSize / 2 + flippedSize,
    center.dy - topHeight / 2, center.dx - rectSize / 2, center.dy);
canvas.drawPath(topPath, paint);

绘制的效果如下,看起来就有日历的感觉了。

翻页动效绘制

翻页动效实际上就是再画一个 Path,这个对象在动画过程中逐步从矩形转换为上半部分的图形,同时通过旋转动效翻转上去 —— 也就是其实我们绘制的是下半部分,只是通过旋转翻上去实现翻页的动效。实现的代码如下,主要的逻辑为:

下边缘的Y 轴位置在 animationValue = 0.0的时候等于下半部分的下边缘Y 轴的位置(rectSize),在 animationValue = 1.0的时候等于上半部分的上边缘Y 轴相对中心点对称位置的,即 center.dy + topHeight,因此得到高度变化的计算代码如下面第2行代码所示。这里增加了一些小的偏移,主要是为了和上下部分有点偏移量,这样能够将翻页和其他部分区分开。

左右两侧的曲度一开始是0,直到翻到中间位置后才显示,这个通过第3到第6行控制,当 animationValue < 0.5的时候,aniamtedFlippedSize 一直是0,即贝塞尔的控制点和起止点在同一条直线上,这样就不会有曲度了,等到animationValue > 0.5后,曲度跟随 animationValue 变化,最终和上半部分的曲度保持一致,这样旋转上去后能够重合。

旋转采用上面我们说的绕任意一点旋转的方式实现,这里我们是绕屏幕的中心,绕 X轴旋转,角度范围是0-180度。

最后是我们更改了翻页的颜色,这个主要是能够通过颜色区分,如果是相同的颜色的话就分不太出来了。

var flippedPath = Path();
var endY = rectSize - 2 + (topHeight - 1 - rectSize) * animationValue;
var animatedFlippedSize = 0.0;
if (animationValue > 0.5) {
  animatedFlippedSize = flippedSize * animationValue;
}
var offsetX = (1 - animationValue) * 4.0;
flippedPath.moveTo(center.dx - rectSize / 2, center.dy);
flippedPath.lineTo(center.dx + rectSize / 2, center.dy);
flippedPath.quadraticBezierTo(
    center.dx + rectSize / 2 + animatedFlippedSize - offsetX,
    center.dy + endY / 2,
    center.dx + rectSize / 2 - offsetX,
    center.dy + endY);

flippedPath.lineTo(center.dx - rectSize / 2 - offsetX, center.dy + endY);
flippedPath.quadraticBezierTo(
    center.dx - rectSize / 2 + animatedFlippedSize,
    center.dy + endY / 2,
    center.dx - rectSize / 2,
    center.dy);
var transform = Matrix4.identity()
  ..translate(center.dx, center.dy, 0.0)
  ..rotateX(pi * animationValue)
  ..translate(-center.dx, -center.dy, 0.0);
var transformedPath = flippedPath.transform(transform.storage);
if (animationValue < 0.5) {
  paint.color = Colors.white;
} else {
  paint.color = Colors.green[300]!;
}
canvas.drawPath(transformedPath, paint);

最终的实现效果如下所示。

总结

本篇介绍了Flutter 绘图中的 Path类的三维空间变换方法和应用,可以看到,基于三维变换可以实现3D效果图形的绘制和实现3D 动效,这在有些特殊绘制的场景中或增添趣味性十分有用。

以上就是利用Flutter绘制出3D效果动画的详细内容,更多关于Flutter 3D动画的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter仿网易实现广告卡片3D翻转效果

    目录 前言 实现思路 1.获取各种距离 2.翻转 完整代码 小结 前言 在逛网易新闻时,发现列表中的广告在你滑动的时候会有一个3D旋转的交互引你的注意,不得不说这些产品为了让用户看广告花样百出,那么今天我们就用Flutter也实现这么一个效果. 先看下网易新闻的效果: OK,先说了我看到这个效果的思路:首先我们看到这个广告卡片在从底部向上滑的时候在完全滑入到显示屏区域内开始3D旋转,到这个卡片顶部到达列表顶部时翻转结束,那我们主要还是需要计算这个广告卡片距离列表底部的距离和距离列表顶部的距离,有

  • Android实现3D层叠式卡片图片展示

    本文实例为大家分享了Android实现3D层叠式卡片图片展示的具体代码,供大家参考,具体内容如下 先看效果 好了效果看了,感兴趣的往下看哦! 整体实现思路 1.重写RelativeLayout 实现 锁定宽高比例的 RelativeLayout 2.自定义一个支持滑动的面板 继承 ViewGroup 3.卡片View绘制 4.页面中使用布局 首先为了更好的展示图片我们重写一下 RelativeLayout 编写一个锁定宽高比例的 RelativeLayout AutoScaleRelativeL

  • Android Flutter实现3D动画效果示例详解

    目录 前言 AnimatedWidget 简介 3D 旋转动画的实现 总结 前言 上一篇我们介绍了 Animation 和 AnimationController 的使用,这是最基本的动画构建类.但是,如果我们想构建一个可复用的动画组件,通过外部参数来控制其动画效果的时候,上一篇的方法就不太合适了.在 Flutter 中提供了 AnimatedWidget 组件用于构建可复用的动画组件.本篇我们用 AnimatedWidget 来实现组件的3D 旋转效果,如下图所示. AnimatedWidge

  • Android实现3D标签云简单效果

    本文实例为大家分享了Android实现3D标签云效果展示的具体代码,供大家参考,具体内容如下 一.关于3D标签云 TagCloudView是一个完全基于Android ViewGroup编写的控件,支持将一组View展示为一个3D标签云,并支持全方向滚动. GitHub中的链接地址 (一)效果 页面上标签的数据可以自己定义,数据页面可以滑动选择. (二)AndroidStudio中使用 1.在build.gradle中添加 compile 'com.moxun:tagcloudlib:1.0.3

  • Flutter 实现酷炫的3D效果示例代码

    此文讲解3个酷炫的3D动画效果. 下面是要实现的效果: Flutter 中3D效果是通过 Transform 组件实现的,没有变换效果的实现: class TransformDemo extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('3D 变换Demo'), ), body: Container( alignm

  • Android实现3D标签云效果

    最近业务需求,要求实现一个3D星球环绕效果,经过百般查找,终于找到了这个功能. 来先看看效果图: 首先还是添加第三方依赖库: compile 'com.moxun:tagcloudlib:1.1.0' 布局: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.an

  • 利用Flutter绘制出3D效果动画

    目录 前言 Path 的 transform 方法 绕任意点旋转 卡片3D 旋转实现 日历翻页效果 总结 前言 本篇我们继续介绍 Flutter 绘图的 Path 的应用.Flutter 的 Path 类提供了一个三维空间的变换方法,可以实现路径在三维空间的平移.旋转等操作,从而可以实现3D 绘制的效果.通过本篇你将了解到: Path的三维转换方法 transform 的使用. 绕三维空间某一点的旋转实现. 卡片3D 旋转动效. 类似日历的三维翻页效果. Path 的 transform 方法

  • Flutter利用Canvas绘制精美表盘效果详解

    目录 前言 初始化 面板 刻度 刻度线 刻度值 指针 时针 分针 秒针 动起来 前言 趁着周末空闲时间使用 Flutter 的 Canvas制作了一个精美表盘. 最终实现的效果还不错,如下: 前面说到使用 Canvas 实现该表盘效果,而在 Flutter 中使用 Canvas 更多的则是继承 CustomPainter 类实现 paint 方法,然后在 CustomPaint 中使用自定义实现的 CustomPainter. 比如这里创建的 DialPainter 使用如下: @overrid

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

    前言 今天分享一个类似"孔雀开屏"的动画效果,打开新的页面时,新的页面从屏幕右上角以圆形逐渐打开到全屏. 先来看下具体的效果 不知道这种效果大家叫什么名字?如果有更合适的名字可以在评论处告诉我,下面来说下如何实现此效果. 在使用Navigator进入一个新的页面时,通常用法如下: Navigator.of(context).push(MaterialPageRoute( builder: (context){ return PageB(); } )); MaterialPageRout

  • 利用模糊实现视觉3D效果实例讲解

    目录 实现一个文字的 3D 变换 实现文字的模糊 使用模糊构建落叶效果 本文较短,将介绍巧用模糊实现视觉 3D 效果的技巧. 我们都知道,在正常的视觉效果中,离我们越近的通常我们会看的越清晰,而离我们较远则相对没那么清晰~ 我们可以利用清晰与模糊两种状态来构建视差效果.像是这样: 而在 CSS 中,我们可以利用模糊滤镜 filter: blur() 与 transform-style: preserve-3d 来实现它们. 实现一个文字的 3D 变换 首先,我们需要实现一个文字的 3D 变换,这

  • 如何利用Matlab绘制出好看的火山图

    这里画了一个示例: 数据来源 绘制效果: 代码及说明: 使用代码时只需要改一开始导入的数据,和代码提示中X坐标区域范围和Y坐标区域范围,完整代码如下所示: % 读取数据 data=readmatrix('volcano.txt'); logFC=data(:,2); padj=data(:,3); DB_not=(padj>0.5)|(logFC<0.5&logFC>-0.5); DB_up=padj<=0.05&logFC>=0.5; DB_down=pad

  • 如何利用Flutter实现酷狗流畅Tabbar效果

    目录 前言 效果图 分析效果 开发思路 FlutterTabbar解析源码 实现步骤 业务使用 写在最后 实现源码 前言 在2021年末,酷狗发布了最新版11.0.0版本,这是一次重大的UI重构,更新完打开着实让我耳目一新.在原有风格上,整个App变得更加清爽,流畅.其中Tabbar的风格让我非常感兴趣,如果用Flutter来实现,或许是一个很有趣的事情. 效果图 分析效果 研究酷狗Tabbar的动画可以发现,默认状态下在当前Tab的中心处展示圆点,滑动时的效果拆分成两个以下部分: 从单个Tab

  • Android利用Camera实现中轴3D卡牌翻转效果

    在Android系统API中,有两个Camera类: android.graphics.Camera android.hardware.Camera 第二个应用于手机硬件中的相机相关的操作,本文讲述的是利用第一个Camera类实现中轴3D转换的卡牌翻转效果,开始之前,先看一下Android系统中的坐标系: 对应于三维坐标系中的三个方向,Camera提供了三种旋转方法: rotateX() rotateY() rotateX() 调用这三种方法,传入旋转角度参数,即可实现视图沿着坐标轴旋转的功能.

  • 利用SurfaceView实现下雨与下雪动画效果详解(Kotlin语法)

    前言 最近打算做一波东西巩固一下自己近期所学所得.话不多说,先看一下最终完成的效果图: 下雨.gif 这里比较懒--第二个图片中还是降雨--不过这不是关键点-- 下雪.gif 录制的mp4,转成了gif.第一个gif设置了帧率,所以看起来可能掉帧比较严重,但是实际上并不会,因为这里我也注意了1s要绘制60帧的问题.阅读本文需要一些基本的View知识和会一些基础Kotlin语法.说实话,就知识点来说,跟Kotlin是没多大关系的,只要懂基本的语法就可以了. 理清思路 在动手前先要理一下思路,从以下

  • Android实现3D翻转动画效果

    Android中并没有提供直接做3D翻转的动画,所以关于3D翻转的动画效果需要我们自己实现,那么我们首先来分析一下Animation 和 Transformation. Animation动画的主要接口,其中主要定义了动画的一些属性比如开始时间,持续时间,是否重复播放等等.而Transformation中则包含一个矩阵和alpha值,矩阵是用来做平移,旋转和缩放动画的,而alpha值是用来做alpha动画的,要实现3D旋转动画我们需要继承自Animation类来实现,我们需要重载getTrans

  • 详解利用Flutter中的Canvas绘制有趣的图形

    目录 简介 等边三角形构建重复之美 绘制彩虹 绘制五角星 总结 简介 上一篇我们介绍了使用 Flutter 的 Canvas 绘制基本图形的示例,简单的示例没什么好玩的,今天这一篇我们来点有趣的,我们会完成如下图形的绘制: 发现数学重复之美:使用等边三角形组合成彩虹伞面. 绘制彩虹. 绘制评分用的五角星. 通过这一篇,我们可以知道自定义形状绘制的基本原理,然后可以在这个基础上绘制你自己想要绘制的图形. 等边三角形构建重复之美 首先我们来绘制等边三角形,其实上一篇我们也有绘制等边三角形,只是那是将

随机推荐