暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

看完这篇你也可以搞定动态曲线绘制

岛上码农 2022-11-24
521

前言

本篇我们来了解一下 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(00));
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);

总结

本篇介绍了 Flutter 路径Path
的工具类 PathMetric
的介绍和应用,通过 PathMetric
我们可以定位到 Path
的指定位长度的位置的信息,也可以通过起始点从 Path
中抽取子路径。有了这些基础,就可以实现很多场景的应用,比如曲线上布局标识或填充,标记指定位置的点等等。


本公众号内回复“源码”可获取《Flutter 入门与实战》系列源码。


文章转载自岛上码农,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论