Path 顾名思义是路径的意思。前文我们讲过Canvas提供了很多方法来绘制各种图形。但是,有时我们的需求不是常规的图形,那么就需要用到本文要讲的Path类。
Canvas里提供了一个drawPath(Path path, Paint paint)方法,来绘制我们的Path对象。
下面就让我们一起来了解一下Path对象。
构造方法
Path()
Path(Path src)
Path提供了两种构造方法,一种是无参的,一种是根据一个Path对象来生成的。
addXXX系列方法
前文讲过Canvas提供了一系列drawXXX的方法,来绘制想矩形,圆,椭圆,圆弧等各种图形。Path,作为路径,当然也提供了对应的方法。不太了解的请移步《Android:视图绘制(一) ——基本的绘图操作Paint和Canvas》
因为方法与前文所讲差别不大,对于这一系列的就不一一介绍了,下面以矩形为例:
addRect(RectF rect, Direction dir)
addRect(float left, float top, float right, float bottom, Direction dir)
Path这一系列方法都是以add开头的,参数RectF和float left, float top, float right, float bottom,前文也有介绍,相信大家都很熟悉。
下面来看 Direction ,路径的方向,其是Path中的一个枚举型变量,并提供了两个可选值
CW 顺时针
CCW 逆时针
// Direction 为 CW 的Path对象
Path pathCW = new Path();
pathCW.addRect(100, 100, 400, 400, Path.Direction.CW);
// Direction 为 CCW 的Path对象
Path pathCCW = new Path();
pathCCW.addRect(100, 500, 400, 800, Path.Direction.CCW);
canvas.drawPath(pathCW, mPaintLine);
canvas.drawTextOnPath("Path.Direction.CW", pathCW, 0, 0, mPaintLine);
canvas.drawPath(pathCCW, mPaintLine);
canvas.drawTextOnPath("Path.Direction.CCW", pathCCW, 0, 0, mPaintLine);
可以看见我们分别以顺时针和逆时针声明了一个Path对象,并调用Canvas的drawPath方法画出来。为了给大家体现出效果,又调用了Canvas的drawTextOnPath,画出文字。
这样,就可以很清晰的看出CW和CCW的区别。
Path还提供了一些图形方法,大致相同。这些方法完全可以用Canvas对应的方法代替,就不多做介绍了。
addArc 圆弧
addRoundRect 圆角矩形
addCircle 圆
addOval 椭圆
以点画线
这部分讲的方法,才是Path类的特别之处,也是我们为什么要用到Path类的原因。
moveTo(float x, float y)
官网解释:Set the beginning of the next contour to the point (x,y).
也就是设置我们要绘制的图形的起点(x,y)。
lineTo(float x, float y)
官网解释:Add a line from the last point to the specified point (x,y). If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
意思是:以之前设置过的最后一个点到这个点(x,y)连线,如果之前没有调用moveTo(),也就是说连起点都没设置,那默认是以(0,0)为起点的。
close()
官网解释:Close the current contour. If the current point is not equal to the first point of the contour, a line segment is automatically added.
意思是闭合我们的图形,如果不是只有一个点的话,就会加一条线。
// 画一个三角形
Path path = new Path();
path.moveTo(100, 100); // 如果不加这句,默认以(0,0)为起点。
path.lineTo(200, 400);
path.lineTo(300, 300);
path.close();
canvas.drawPath(path, mPaintLine);
可以看出,当调用close方法时,以最后一个点(300,300)到起点(100,100)做了一条连线。
rMoveTo(float x, float y)
官网解释:Set the beginning of the next contour relative to the last point on the previous contour. If there is no previous contour, this is treated the same as moveTo().
可以看见这个方法比前面的moveTo,多了一个字母 r .这里 r 的意思就是 relative(相对)的意思,从官网的解释上也能看出,就是在前一个点的基础上增加了(x,y),如果是第一个点,等同于 moveTo().
rLineTo(float x, float y)
官网解释:Same as lineTo, but the coordinates are considered relative to the last point on this contour. If there is no previous point, then a moveTo(0,0) is inserted automatically.
这个方法较lineTo也是多了一个 relative(相对)的意思。
Path path = new Path();
path.moveTo(100, 100); // 如果不加这句,默认以(0,0)为起点。
path.lineTo(200, 400);
path.lineTo(300, 300);
path.close();
path.rMoveTo(100, 100); // 在上一个点(300,300)基础上加了(100,100),所以这个点是(400,400)
path.rLineTo(100, 100); // 在上一个点(400,400)基础上加了(100,100),所以这个点是(500,500)
canvas.drawPath(path, mPaintLine);
值得一说的是,上面的例子中,Paint的填充模式为Paint.Style.STROKE。如果我们把Paint的填充模式设置为Paint.Style.FILL的话,直线是不会绘制出来的,因为直线,没有可供填充的区域。
到此,讲的Path都是以直线连接各个点,来构成图形。其实Path中还封装了贝塞尔曲线(有没有很高大上,其实用起来还是蛮简单的),可以绘制曲线的效果。
贝塞尔曲线有控制点的概念,通过控制点来绘制出特定的曲线。所以,只有两个点的话,就是一条直线。
quadTo(float x1, float y1, float x2, float y2)
官方解释:Add a quadratic bezier from the last point, approaching control point (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
意思就是增加一个二次的贝塞尔曲线,以 moveTo(x,y) 为起点(如果没有设置默认为(0,0)),(x2,y2)为终点, (x1,y1)为控制点。
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
官方解释:Add a cubic bezier from the last point, approaching control points (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
cubicTo 方法构建的是一个三次的贝塞尔曲线,以第一个点为起点,(x3,y3)为终点,其余点为控制点
看一个例子:
// 二阶贝塞尔曲线
Path pathBezier = new Path();
pathBezier.moveTo(100, 100);
pathBezier.quadTo(200, 400, 100, 600);
canvas.drawPath(pathBezier, mPaintLine);
// 以二阶贝塞尔曲线的所有点连线
Path path = new Path();
path.moveTo(100, 100);
path.lineTo(200, 400);
path.lineTo(100, 600);
canvas.drawPath(path, mPaintText);
// 三阶贝塞尔曲线
Path pathCubic = new Path();
pathCubic.moveTo(400,100);
pathCubic.cubicTo(300,300,500,400,400,600);
canvas.drawPath(pathCubic, mPaintLine);
// 以三阶贝塞尔曲线的所有点连线
path.moveTo(400, 100);
path.lineTo(300, 300);
path.lineTo(500, 400);
path.lineTo(400, 600);
canvas.drawPath(path, mPaintText);
跟前面的一样,quadTo和cubicTo都有其对应的相对方法(即前缀为 r 的)rQuadTo和rCubicTo,也是相对的意思,值得注意的是因为这个方法参数不是一个点,所有的相对都是针对第一个点的。
rQuadTo(float dx1, float dy1, float dx2, float dy2) dx2和dy2,是相对于 dx1和dy1的。
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) x2,y2 和x3,y3都是相对于 x1,y1的。
arcTo(RectF oval, float startAngle, float sweepAngle)
arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
官方解释: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.
意思就是说在Path上加一个圆弧,如果Path上的最后一个点不是圆弧的起点,就会在最后一个点和圆弧起点做一个连线。如果path是空的话,就是没设置过任何数据的时候,会把圆弧的起点最为Path的起点。
Path path = new Path();
path.moveTo(100, 100);
RectF rectF = new RectF(200, 200, 400, 400);
path.arcTo(rectF, 0, 80, false);
canvas.drawPath(path, mPaintLine);
canvas.drawRect(rectF, mPaintLine);