前言

本篇我们继续介绍 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动画的资料请关注Devmax其它相关文章!

利用Flutter绘制出3D效果动画的更多相关文章

  1. 基于HTML5 WebGL的3D机房的示例

    这篇文章主要介绍了基于HTML5 WebGL的3D机房的示例的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Canvas实现贝赛尔曲线轨迹动画的示例代码

    这篇文章主要介绍了Canvas实现贝赛尔曲线轨迹动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. HTML5 直播疯狂点赞动画实现代码 附源码

    为了烘托直播间的氛围,直播相对于普通视频或者文本内容,点赞动作通常无限次,引导用户疯狂点赞,今天小编给大家分享HTML5 直播疯狂点赞动画实现代码 附源码,感兴趣的朋友一起看看吧

  4. CSS中实现动画效果-附案例

    这篇文章主要介绍了 CSS中实现动画效果并附上案例代码及实现效果,就是CSS动画样式处理,动画声明需要使用@keyframes name,后面的name是人为定义的动画名称,下面我们来看看文章的具体实现内容吧,需要的小伙伴可以参考一下

  5. 基于canvas的骨骼动画的示例代码

    这篇文章主要介绍了基于canvas的骨骼动画的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. html5如何在Canvas中实现自定义路径动画示例

    本篇文章主要介绍了html5如何在Canvas中实现自定义路径动画示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. 基于HTML5+Webkit实现树叶飘落动画

    本文给大家分享一段实例代码给大家介绍基于HTML5+Webkit实现树叶飘落动画效果,需要的朋友参考下吧

  9. 基于HTML5 Canvas的3D动态Chart图表的示例

    这篇文章主要介绍了基于HTML5 Canvas的3D动态Chart图表的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Html5页面内使用JSON动画的实现

    这篇文章主要介绍了Html5页面内使用JSON动画的实现的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部