携手创作,共同成长!这是我参与「日新计划 8 月更文应战」的第3天,点击查看活动详情
前言
本篇咱们持续介绍 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 动效,这在有些特殊制作的场景中或增加趣味性十分有用。
本篇源码已上传至:绘图相关代码,文件名为:path_matrix_demo.dart
。
我是岛上码农,微信大众号同名,这是Flutter 入门与实战的专栏文章,供给体系化的 Flutter 学习文章。对应源码请看这儿:Flutter 入门与实战专栏源码。如有问题能够加本人微信交流,微信号:
island-coder
。:觉得有收成请点个赞鼓励一下!
:保藏文章,便利回看哦!
:谈论交流,相互进步!