Path类常用API介绍

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011118524/article/details/78348138
/**
 * The Path class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves.
 * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
 * (based on the paint's Style), or it can be used for clipping or to draw
 * text on a path.
 */

翻译: Path封装了由直线和曲线(二次,三次贝塞尔曲线)构成的几何路径。你能用Canvas中的drawPath来把这条路径画出来(同样支持Paint的不同绘制模式),也可以用于剪裁画布和根据路径绘制文字。我们有时会用Path来描述一个图像的轮廓,所以也会称为轮廓线(轮廓线仅是Path的一种使用方法,两者并不等价)。

从注释中可以看出,Path类封装了一些复合的几何路径,其中包括直线,二次曲线,三次曲线等,以及做图表什么的都可以。我们来看一下他的源代码,其中有一个内部类Direction,在我们调用Path的一系列add方法往Path里面添加图形的时候,就会需要提供一个方向,比如我们调用addRect方法添加一个矩形Rect(100,100,200,200)的时候,假设该矩形的四个顶点为ABCD,坐标分别为A(100,100),B(200,100),C(200,200),D(200,100),在add到Paht里的时候,Path会根据指定的方向,来解析每个点构成的直线,如果指定的方向是顺时针的话,则矩形的四条边添加和绘制的顺序依次是AB,BC,CD,DA;如果是逆时针的话,则依次为AD,DC,CB,BA,下面会通过代码实例来验证我们的想法。

Direction的源码如下:

/**
* Specifies how closed shapes (e.g. rects, ovals) are oriented when they
* are added to a path.
*/
public enum Direction {
/** 顺时针方向*/
CW  (0),    // must match enum in SkPath.h
/** 逆时针方向 */
CCW (1);    // must match enum in SkPath.h

Direction(int ni) {
    nativeInt = ni;
}
final int nativeInt;
}

测试代码如下:

mPath.addRect(200, 100, 500, 300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
mPath.reset();
mPath.addRect(200, 400, 500, 600, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);

效果图如下:
这里写图片描述
从实现的效果图中,我们发现,在绘制规则图形的时候,顺时针和逆时针基本没有差别,为了看出差异,我们修改一下上面的代码如下:

setLayerType(LAYER_TYPE_SOFTWARE, null);//需要关闭硬件加速功能,否则画出的形状是不闭合的,

mPath.addRect(100, 100, 300, 300, Path.Direction.CW);
mPath.setLastPoint(50, 200);
mPath.close();
canvas.drawPath(mPath, mPaint);

mPath.reset();
mPath.addRect(100, 400, 300, 600, Path.Direction.CCW);
mPath.setLastPoint(50, 500);
mPath.close();//使图形闭合
canvas.drawPath(mPath, mPaint);

实现效果如下:
这里写图片描述

当我们指定最后一个绘制点的时候,顺时针和逆时针就可以看出差异了。

当我们在指定的路径上画文字的时候,文字的方向就会跟我们添加的路径时所使用的方向保持一致。
如:

mPath.addCircle(400, 400, 300, Path.Direction.CW);
canvas.drawPath(mPath, mPaint);
canvas.drawTextOnPath("顺时针方向绘制文字", mPath, 25, 25, mPaint);

mPath.reset();
mPath.addCircle(400, 1100, 300, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);
canvas.drawTextOnPath("逆时针方向绘制文字", mPath, 25, 25, mPaint);

效果图如下:
这里写图片描述

上面介绍了一下Path.Direction类的基本用法,接下来就介绍Path常用Api。

Path常用Api简述:

方法名称 方法描述
moveTo 移动到下一次操作的起点位置
setLastPoint 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
lineTo 添加上一个点到当前点之间的直线到Path中
close 连接第一个点到最后一个点,使之形成一个闭合区域
addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
isEmpty 判断Path是否为空
isRect 判断path是否是一个矩形
set 用新的路径替换当前路径所有内容
offset 对当前路径之前的操作进行偏移(不会影响之后的操作)
quadTo, cubicTo 分别为添加二阶和三阶贝塞尔曲线的方法
rMoveTo, rLineTo, rQuadTo, rCubicTo 不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点(即以当前点为坐标原点)坐标系(偏移量)
setFillType, getFillType, isInverseFillType, toggleInverseFillType 设置,获取,判断和切换填充模式
incReserve 提示Path还有多少个点等待加入(这个方法貌似会让Path优化存储结构)
op 对两个Path进行布尔运算(即取交集、并集等操作)
computeBounds 计算Path的边界
reset, rewind 清除Path中的内容,reset不保留内部数据结构,但会保留FillType;rewind会保留内部的数据结构,但不保留FillType
transform 矩阵变换

Path常用Api实例详解

在UI绘制的时候,硬件加速在某些情况下会引起一些绘制问题,如上面的绘制,在没有关闭硬件加速的时候,绘制的图形是不闭合的,所以为了避免不必要的麻烦,在绘制之前关闭硬件加速,关闭的方式有如下几种方式:

  • setLayerType(LAYER_TYPE_SOFTWARE, null);在自定义控件初始化的时候设置
  • 在AndroidMenifest文件中application节点下添上 android:hardwareAccelerated=”false”

Path添加圆弧的方法:addArc,arcTo

// addArc
public void addArc (RectF oval, float startAngle, float sweepAngle);
// arcTo
public void arcTo (RectF oval, float startAngle, float sweepAngle);
/**
 * Append the specified arc to the path as a new contour. If the start of
 * the path is different from the path's current last point, then an
 * automatic lineTo() is added to connect the current contour to the
 * start of the arc. However, if the path is empty, then we call moveTo()
 * with the first point of the arc.
 *
 * @param startAngle  开始角度
 * @param sweepAngle  偏移角度,即绘制多少角度的圆弧
 * @param forceMoveTo true把
 */
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

注释翻译:添加一个指定的圆弧到Path中,如果被添加的圆弧的起点与当前Path路径的最后一个点不相同,那么将会自动的调用lineTo方法,把前路径最后一个点与圆弧的起点用直线连接起来。如果当前Path为空,则调用moveTo方法,把圆弧的第一个点设置为起点。

通过注释我们可以了解到,如果forceMoveTo参数为true,那么会调用moveTo方法把被圆弧的起点设置为当前路径的最后一个点,这样当前Path路径的最后一个点的坐标与被添加圆弧的起点坐标是一样的,这样就不会调用lineTo方法去连线了,如果forceMoveTo参数为false,那么当前Path路径的最后一个点没有改变,该是啥就是啥,如果与被添加的圆弧起点不一致,则会调用lineTo方法添加一条连线,把当前Path的最后一个点与圆弧的起点连接起来。默认为false。

实例代码:

Path path = new Path();
path.lineTo(100, -100);
path.arcTo(new RectF(-300, -300, -100, -100), 0, 270);//
path.arcTo(new RectF(-50, -50, 100, 100), 0, 270, true);
canvas.drawPath(path, paint);

效果图如下:
这里写图片描述

说明:

  • path.lineTo(100, -100);方法添加了一条直线1,执行完后,Path的最后一个点为A,
  • path.arcTo(new RectF(-300, -300, -100, -100), 0, 270);向Path中添加了一个圆弧2,arcTo方法默认forceMoveTo参数为false,所以在执行arcTo方法的时候,发现当前Path的最后一个点是A,但被添加的圆弧2的起点B与A的坐标不一致,所以会调用lineTo方法,把A和B两点连接起来,于是就有了线条4。执行顺序:先画直线4,在画圆弧2。所以执行完该代码后,Path的最后一个点为C。
  • path.arcTo(new RectF(-50, -50, 100, 100), 0, 270, true);向Path中添加一个圆弧3,此时forceMoveTo参数为true,则会先调用moveTo方法(参数为D的坐标),这时当前Path的最后一个点的就变成了D,与圆弧3的起点坐标是一样的,所以就没有在调用lineTo方法去画直线了。执行完该代码后,当前Path的最后一个点为E。

总结:addArc就是简单的添加一条圆弧,当arcTo方法方法的forceMoveTo=true的时候,与addArc方法等价。

推荐一篇写的很好的博客:安卓自定义View进阶-Path之基本操作

猜你喜欢

转载自blog.csdn.net/u011118524/article/details/78348138