Android自定义控件(三 .0)Path的基本操作

前面http://www.jianshu.com/p/35765aa6f7d9 所讲的绘制的图形都是基本的简单图形,如矩形,员,圆弧等。如果对于一些复杂的图形(五角星,心形)的绘制,前面的绘图方法就无能为力了。而使用Path不仅可以绘制简单的图形,还能复制一些复杂的图形。
Google官网上Path的链接为:https://developer.android.google.cn/reference/android/graphics/Path.html
google官网上对path的解释为:

  • 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类封装了直线段,二次bezier曲线,三次bezier曲线等几何路径,可以通过canvas.drawPath(path, paint)方法画出,画笔的类型可以是filled 或者 stroked,可以用于通过路径裁剪或者绘制文本。
Path的相关方法
作用 相关方法 备注
移动起点 [moveTo](https://developer.android.google.cn/reference/android/graphics/Path.html#moveTo(float, float))(float x, float y) Set the beginning of the next contour to the point (x,y).
设置终点 [setLastPoint](https://developer.android.google.cn/reference/android/graphics/Path.html#setLastPoint(float, float))(float dx, float dy) Sets the last point of the path.
连接直线 [lineTo](https://developer.android.google.cn/reference/android/graphics/Path.html#lineTo(float, float))(float x, float y) Add a line from the last point to the specified point (x,y).
闭合路径 close() Close the current contour.
添加内容 [addArc](https://developer.android.google.cn/reference/android/graphics/Path.html#addArc(float, float, float, float, float, float))、[addCircle](https://developer.android.google.cn/reference/android/graphics/Path.html#addCircle(float, float, float, android.graphics.Path.Direction))、[addOval](https://developer.android.google.cn/reference/android/graphics/Path.html#addOval(android.graphics.RectF, android.graphics.Path.Direction))、[addPath](https://developer.android.google.cn/reference/android/graphics/Path.html#addPath(android.graphics.Path, android.graphics.Matrix))、[addRect](https://developer.android.google.cn/reference/android/graphics/Path.html#addRect(android.graphics.RectF, android.graphics.Path.Direction))、[addRoundRect](https://developer.android.google.cn/reference/android/graphics/Path.html#addRoundRect(android.graphics.RectF, float, float, android.graphics.Path.Direction))、[arcTo](https://developer.android.google.cn/reference/android/graphics/Path.html#arcTo(android.graphics.RectF, float, float, boolean)) 添加( 圆弧、 圆, 椭圆,路径,矩形, 圆角矩形, ) 到当前Path
是否为空 isEmpty() Returns true if the path is empty (contains no lines or curves)
是否为矩形 isRect(RectF rect) Returns true if the path specifies a rectangle.
替换路径 set(Path src) Replace the contents of this with the contents of src.
偏移路径 [offset](https://developer.android.google.cn/reference/android/graphics/Path.html#offset(float, float)) Offset the path by (dx,dy)
重置路径 reset()、rewind() Clear any lines and curves from the path, making it empty./Rewinds the path: clears any lines and curves from the path but keeps the internal data structure for faster reuse.
rXxx方法 [rCubicTo](https://developer.android.google.cn/reference/android/graphics/Path.html#rCubicTo(float, float, float, float, float, float))、[rLineTo](https://developer.android.google.cn/reference/android/graphics/Path.html#rLineTo(float, float))、[rMoveTo](https://developer.android.google.cn/reference/android/graphics/Path.html#rMoveTo(float, float))、[rQuadTo](https://developer.android.google.cn/reference/android/graphics/Path.html#rQuadTo(float, float, float, float)) 不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)
贝塞尔曲线 [quadTo](https://developer.android.google.cn/reference/android/graphics/Path.html#quadTo(float, float, float, float))、[cubicT](https://developer.android.google.cn/reference/android/graphics/Path.html#cubicTo(float, float, float, float, float, float)) 分别为二次和三次贝塞尔曲线的方法
矩阵操作 transform Transform the points in this path by matrix
填充模式 setFillTypetoggleInverseFillType()、isInverseFillType()、getFillType() 设置、切换、判断和获取填充模式
计算边界 [computeBounds](https://developer.android.google.cn/reference/android/graphics/Path.html#computeBounds(android.graphics.RectF, boolean)) Compute the bounds of the control points of the path, and write the answer into bounds.
布尔操作 [op](https://developer.android.google.cn/reference/android/graphics/Path.html#op(android.graphics.Path, android.graphics.Path, android.graphics.Path.Op)) Set this path to the result of applying the Op to the two specified paths
lineTo

首先先要说的是lineTo ,lineTo的方法如下:
[lineTo](https://developer.android.google.cn/reference/android/graphics/Path.html#lineTo(float, float))(float x, float y)
Add a line from the last point to the specified point (x,y)
在上次的结束点和指定的点之间添加一条line,the last point是上次操作结束的点,如果没有上次结束的点呢,额,那就默认为坐标原点。
现在测试一下:

 int mWidth = getWidth();
int mHeight = getHeight();
canvas.translate(mWidth/2,mHeight/2);  //坐标移动到屏幕中心
Path path=new Path();       //创建Path
path.lineTo(200,200);
path.lineTo(200,-200);
canvas.drawPath(path,mPaint2);  //绘制Path
Image.png

在例子中,我们调用了两次lineTo,第一次调用时,因为之前没有调用过,所以默认点是坐标原点,第二次调用时,因为上次调用的结束点是(200,200),所以这次lineTo是(200,200)到(200,-200)之间的连线。

moveTo 和 setLastPoint:

[moveTo](https://developer.android.google.cn/reference/android/graphics/Path.html#moveTo(float, float))(float x, float y) :Set the beginning of the next contour to the point (x,y).
[setLastPoint](https://developer.android.google.cn/reference/android/graphics/Path.html#setLastPoint(float, float))(float dx, float dy):Sets the last point of the path
这两个方法看起来比较类似,其实是有很大不同的,如下表所示:

方法名 | 简介 | 是否影响之前的操作 | 是否影响之后操作
------------|---------|--------------|--------------|------------
[moveTo](https://developer.android.google.cn/reference/android/graphics/Path.html#moveTo(float, float))(float x, float y)|设置下次Path的起点|否|是
[setLastPoint](https://developer.android.google.cn/reference/android/graphics/Path.html#setLastPoint(float, float))(float dx, float dy)|设置上次操作最后一个点的位置|是|是
直接上代码:

canvas.translate(mWidth / 2, mHeight / 2);
Path path = new Path();
path.lineTo(200,200);
path.moveTo(200,0);
path.lineTo(200,-200);
canvas.drawPath(path,mPaint2);
Image.png

moveTo只改变下次操作的起点,在执行完第一次LineTo的时候,本来的默认点位置是(200,200),但是moveTo将其改变成为了(200,0),所以在第二次调用lineTo的时候就是连接(200,0) 到 (200,-200) 之间的直线。

  • 下面是setLastPoint
canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
 path.lineTo(200,200);
 canvas.drawPoint(200,200,mPaint2);
 path.setLastPoint(200,100);
 path.lineTo(200,-200);
 canvas.drawPath(path,mPaint2);

setLastPoint是重置上一次操作的最后一个点,在执行完第一次的lineTo的时候,最后一个点是(200,200),而setLastPoint更改最后一个点为(200,100),所以在实际执行的时候,第一次的lineTo就不是从原点到(200,200)的连线了,而变成了从原点到C(200,100)之间的连线了。

在执行完第一次lineTo和setLastPoint后,最后一个点的位置是(200,100),所以在第二次调用lineTo的时候就是(200,100) 到 (200,-200) 之间的连线。

Image.png
close

close():Close the current contour
close方法用于连接当前最后一个点和最初的一个点(如果两个点不重合的话),最终形成一个封闭的图形。

canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
path.lineTo(200,200); path.lineTo(200,-200);
path.close();
canvas.drawPath(path,mPaint2);
Image.png

注意:close的作用是封闭路径,与连接当前最后一个点和第一个点并不等价。如果连接了最后一个点和第一个点仍然无法形成封闭图形,则close什么 也不做。

addXXX和arcTo

这次方法主要是在Path中添加基本图形,重点区分addArc与arcTo。

类型 解释 说明
CW clockwise 顺时针
CCW counter-clockwise 逆时针
addPath

addPath(Path src) :Add a copy of src to the path
[addPath](https://developer.android.google.cn/reference/android/graphics/Path.html#addPath(android.graphics.Path, float, float))(Path src, float dx, float dy):Add a copy of src to the path, offset by (dx,dy)
[addPath](https://developer.android.google.cn/reference/android/graphics/Path.html#addPath(android.graphics.Path, android.graphics.Matrix))(Path src, Matrix matrix):Add a copy of src to the path, transformed by matrix
addPath方法很明了,就是把两个Path合并为一个
第二个方法是将src平移后再合并在一起
第三个方法是将src进行Matrix变换后再合并到一起

 canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
Path src=new Path();
path.addRect(-200,-200,200,200,Path.Direction.CW);
src.addCircle(0,0,100,Path.Direction.CW);
path.addPath(src,0,-200);
canvas.drawPath(path,mPaint2);
Image.png
addArc与arcTo

[addArc](https://developer.android.google.cn/reference/android/graphics/Path.html#addArc(android.graphics.RectF, float, float))(RectF oval, float startAngle, float sweepAngle)--- Add the specified arc to the path as a new contour.
[addArc](https://developer.android.google.cn/reference/android/graphics/Path.html#addArc(float, float, float, float, float, float))(float left, float top, float right, float bottom, float startAngle, float sweepAngle)---Add the specified arc to the path as a new contour
[arcTo](https://developer.android.google.cn/reference/android/graphics/Path.html#arcTo(android.graphics.RectF, float, float, boolean))(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)---Append the specified arc to the path as a new contour.
[arcTo](https://developer.android.google.cn/reference/android/graphics/Path.html#arcTo(float, float, float, float, float, float, boolean))(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)--Append the specified arc to the path as a new contour.
[arcTo](https://developer.android.google.cn/reference/android/graphics/Path.html#arcTo(android.graphics.RectF, float, float, boolean))(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)---Append the specified arc to the path as a new contour

方法名 作用 区别
addArc 添加一个圆弧到path 直接添加一个圆弧到path
arcTo 添加一个圆弧到path 如果圆弧的起点和上次最后一个坐标点不同,就连接两个点

另外,可以看到arcTo方法最后一个参数是个boolean类型的,forceMoveTo,有什么作用呢

forceMoveTo 含义
true 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点
false 不移动,而是连接最后一个点与圆弧起点

addArc

canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
path.lineTo(100,100);
RectF oval=new RectF(0,0,300,300);
path.addArc(oval,0,270);
canvas.drawPath(path,mPaint2);
Paste_Image.png

arcTo

canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
path.lineTo(100,100);
RectF oval=new RectF(0,0,300,300);
path.arcTo(oval,0,270);
canvas.drawPath(path,mPaint2);
Paste_Image.png
isEmpty、 isRect、isConvex、 set 和 offset
dst状态 效果
dst不为空 将当前path平移后的状态存入dst中,不会影响当前path
dst为空(null) 平移将作用于当前path,相当于第一种方法
canvas.translate(mWidth/2,mHeight/2);
Path path=new Path();
path.addCircle(0,0,100,Path.Direction.CW);
Path dst=new Path();
 path.offset(300,0,dst);
canvas.drawPath(path,mPaint2);
path.offset(300,0);
canvas.drawPath(path,mPaint2);

Paste_Image.png

代码下载地址
https://github.com/baojie0327/ViewAndGroup

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • 最近项目中要实现加速球效果。是时候该学习一波了,好了废话不多说,记笔记,还是从自己发憷的自定义view开始。 先来...
    laifrog阅读 1,446评论 0 4
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。系列教程:Android开发之从零开始系列大家要是看到有错误的...
    Anlia阅读 20,409评论 1 24
  • 什么是Path? 我们先看看Android官方文档给出的定义: The Path class encapsulat...
    一团捞面阅读 6,658评论 13 127
  • 系列文章之 Android中自定义View(一)系列文章之 Android中自定义View(二)系列文章之 And...
    YoungerDev阅读 4,367评论 3 11
  • 我想,六岁以前的事我大概什么都不记得了吧。还没有上学的时候,应该一切都是无忧无虑的样子。 不过清楚地记得一个场景,...
    用你的感觉阅读 98评论 0 0