看完这篇,你也可以搞定有趣的动态曲线绘制
前言
接下来我们来了解一下 Path
类的一些特性。Path
类用于描述绘制路径,可以实现绘制线段、曲线、自定义形状等功能。本篇我们介绍 Path
的一个描述类 PathMetric
的应用。通过本篇你会了解以下两方面的内容:
PathMetric
类简介。PathMetric
的应用。
PathMetric 简介
PathMetric
是一个用于测量 Path
和抽取子路径(sub-paths) 的工具,通过 Path
类的 computeMetrics
方法可以返回一组PathMetric
类。为什么是一组,而不是一个呢?这是因为 Path
可能包含多个不连续的子路径,比如通过 moveTo
可以重新开启新的一段路径。
通过 PathMetric
可以获取到 Path
的长度,路径是否闭合,以及某一段路径是否是 Path
的子路径。PathMetrics
是一个迭代器,因此在不获取其中的 PathMetric
对象时,并不会实际进行 Path 的相关计算,这样可以提高效率。另外需要注意的是,通过 computeMetrics
方法计算得到的是一个当前Path 对象的快照,如果在之后更改了 Path
对象,并不会进行更新。
我们来看一下 PathMetric
的一些属性和方法。
length
:Path
对象其中一段(独立的)的长度;isClosed
:判断Path
对象是否闭合;contourIndex
:当前对象在PathMetrics
中的次序;getTangentForOffset
:这个方法通过距离起点的长度的偏移量(即从0 到length
中的某个位置)返回一个Tangent
对象,通过这个对象可以获取到Path
某一段路径途中的任意一点的位置以及角度。以下面的图形为例,从点(0, 0)到点(2, 2)的线段总长度为2.82,如果我们通过getTangentForOffset
获取距离起始点1.41 的位置的Tangent
对象,就会得到该位置的坐标是(1, 1),角度是45度(实际以弧度的方式计算)。
extractPath
:通过距离 Path 起点的开始距离和结束距离获取这段路劲的子路径,如下图所示。
PathMetric 应用
我们来通过 PathMetric
实现下面动图的效果。
这张图最开始绘制的是一条贝塞尔曲线,是通过 Path
自带的贝塞尔曲线绘制的,代码如下所示。
Path path = Path();
final curveHeight = 60.0;
final stepWidth = size.width / 4;
path.moveTo(0, size.height / 2);
path.quadraticBezierTo(size.width / 2 - stepWidth,
size.height / 2 - curveHeight, size.width / 2, size.height / 2);
path.quadraticBezierTo(size.width / 2 + stepWidth,
size.height / 2 + curveHeight, size.width, size.height / 2);
quadraticBezierTo
这个方法就是从 Path
当前的终点到参数3,4(参数名为 x2,y2)绘制一条贝塞尔曲线,控制点为参数1,2(参数名为 x1,y1)。
动画过程中曲线上的红色圆点就是通过 PathMetric
得到的,动画对象 Animation
的值从0-1变化,我们通过这个值乘以曲线的长度就能得到getTangentForOffset
方法所需的偏移量,然后就可以确定动画过程中绘制圆点的位置了,代码如下所示。
for (var pathMetric in metrics) {
var tangent =
pathMetric.getTangentForOffset(pathMetric.length * animationValue);
paint.style = PaintingStyle.fill;
canvas.drawCircle(tangent!.position, 4.0, paint);
}
接下来是动画过程中的我们看到红色曲线会逐步覆盖蓝色曲线,这就是用 extractPath
获取子路径完成的,在动画过程,我们控制 extractPath
的结束位置,就可以逐步完成原有曲线的覆盖了,实现代码只有两行,如下所示。
var subPath =
pathMetric.extractPath(0.0, pathMetric.length * animationValue);
canvas.drawPath(subPath, paint);
最后是底下的填充,填充我们使用了渐变色,这个利用了之前我们讲过的Paint
对象的 shader
属性实现,具体可以参考之前的文章。填充其实就是一段闭合的 Path,只是在动画过程中控制右边绘制的边界就可以了,然后上面跟随曲线的部分还是基于子路径完成的。填充部分实现代码如下。
var fillPath = Path();
fillPath.moveTo(0, size.height);
fillPath.lineTo(0, size.height / 2);
fillPath.addPath(subPath, Offset(0, 0));
fillPath.lineTo(tangent.position.dx, size.height);
fillPath.lineTo(0, size.height);
paint.shader = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.red[400]!, Colors.blue[50]!],
).createShader(Rect.fromLTRB(
0,
size.height / 2 - curveHeight,
size.width,
size.height,
));
canvas.drawPath(fillPath, paint);
完整代码已经提交至:绘图相关代码,文件名为:path_metrics_demo.dart
。
总结
本篇介绍了 Flutter 路径Path
的工具类 PathMetric
的介绍和应用,通过 PathMetric
我们可以定位到 Path
的指定位长度的位置的信息,也可以通过起始点从 Path
中抽取子路径。有了这些基础,就可以实现很多场景的应用,比如曲线上布局标识或填充,标记指定位置的点等等。
链接:https://juejin.cn/post/7122790277315559437
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。