Path 使用方法详解
此篇是看了一名来自2.5次元的魔法师的文章后做的笔记,原文http://www.gcssloop.com/customview/Path_Bezier,大家可以看下,文很棒
1. 第一组:moveTo、setLastPoint 、lineTo 、close
方法:lineTo
public void lineTo (float x, float y)
例:画两条线
public PathView1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化画笔
mPaint = new Paint(); // 创建画笔
mPaint.setColor(Color.BLACK); // 画笔颜色 - 黑色
mPaint.setStyle(Paint.Style.STROKE); // 填充模式 - 描边
mPaint.setStrokeWidth(10); // 边框宽度 - 10
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//获取宽高
width = h;
height = w;
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
Path path = new Path(); // 创建Path
path.lineTo(200, 200); // lineTo 从默认点0,0到 200,200
path.lineTo(200, 0); //再从200,200 到点 200,0
canvas.drawPath(path, mPaint); // 绘制Path
}
结果如图,黑色线图像为结果,图中添加坐标系,有利于理解
Path 默认点是坐标原点0,0
事例代码中调用了两次lineTo,
第一次:path.lineTo(200, 200); //从0,0 到点A(200,200)的连线
第二次:path.lineTo(200, 0);//从A(200,200) 到点 B(200,0)的连线
方法 moveTo 和 setLstPoint
// moveTo
public void moveTo (float x, float y)
// setLastPoint
public void setLastPoint (float dx, float dy)
方法名 | 简介 | 是否影响之前操作 | 是否影响之后操作 |
---|---|---|---|
moveTo | 移动下一次操作的起点位置 | 否 | 是 |
setLastPoint | 设置之前操作的最后一个点位置 | 是 | 是 |
方法 moveTo
例:
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
Path path = new Path(); // 创建Path
path.lineTo(200, 200); // lineTo 从默认点0,0到 200,200
path.moveTo(200, 100); // moveTo 改变下一个点开始的位置
path.lineTo(200, 0); // 由于moveTo改变了开始位置,所以从200,100 到点 200,0
canvas.drawPath(path, mPaint); // 绘制Path
moveTo只改变下次操作的起点,在执行完第一次LineTo的时候,本来的默认点位置是A(200,200),但是moveTo将其改变成为了C(200,100),所以在第二次调用lineTo的时候就是连接C(200,100) 到 B(200,0) 之间的直线
方法setLstPoint
例:
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
Path path = new Path(); // 创建Path
path.lineTo(200, 200); // lineTo 从默认点0,0到 200,200
// path.moveTo(200, 100); // moveTo 改变下一个点开始的位置
path.setLastPoint(200,100); // setLastPoint 改变上一个点结束的位置
path.lineTo(200, 0); // 由于moveTo改变了开始位置,所以从200,100 到点 200,0
canvas.drawPath(path, mPaint); // 绘制Path
效果:
在执行完第一次的lineTo的时候,最后一个点是A(200,200),而setLastPoint更改最后一个点为B(200,200)为(200,100),所以在实际执行的时候,第一次的lineTo就不是从原点O到A(200,200)的连线了,而变成了从原点O到C(200,100)之间的连线了。
方法 close
public void close()
用于连接当前最后一个点和最初的点(如果两个点不重合),形成一个闭合的图形
结果:
2. 第二组:addXxx 与 arcTo
第一类(基本形状)
// 圆形
public void addCircle (float x, float y, float radius, Path.Direction dir)
// 椭圆
public void addOval (RectF oval, Path.Direction dir)
// 矩形
public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
public void addRect (RectF rect, Path.Direction dir)
// 圆角矩形
public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)
最后一个参数都是Path.Direction,意思是方向,绘制时点是你是逆时针还是顺时针,在添加图形时确定闭合顺序(各个点的记录顺序)
类型 | 含义 |
---|---|
CW | 顺时针 |
CCW | 逆时针 |
例子:画一个矩形,顺时针
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心
Path path = new Path();
path.addRect(-200, -200, 200, 200, Path.Direction.CW);//顺时针
canvas.drawPath(path, mPaint);
结果:
其实顺时针和逆时针的表面结果是一样的,只是过程不同,是怎么画成的
第二类方法(Path)
// path
public void addPath (Path src)
public void addPath (Path src, float dx, float dy)
public void addPath (Path src, Matrix matrix)
第一个方法:将两个Path合并成为一个
第二个方法比第一个方法多出来的两个参数是将src进行了位移之后再添加进当前path中。
第三个方法是将src添加到当前path之前先使用Matrix进行变换。
例子:
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
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);//将圆形添加到矩形的上 0,200的位置
canvas.drawPath(path,mPaint);
结果:
第三类方法(addArc与arcTo)
// addArc
public void addArc (RectF oval, float startAngle, float sweepAngle)
// arcTo
public void arcTo (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
方法区别
名称 | 作用 | 区别 |
---|---|---|
addArc | 添加一个圆弧到path | 直接添加一个圆弧到path中 |
arcTo | 添加一个圆弧到path | 添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点 |
参数含义
参数 | 含义 |
---|---|
oval | 圆弧的外切矩形 |
startAngle | 开始角度 |
sweepAngle | 扫过角度(-360 <= sweepAngle < 360) |
forceMoveTo | 是否强制使用MoveTo |
sweepAngle取值范围是 [-360, 360),不包括360,当 >= 360 或者 < -360 时将不会绘制任何内容, 对于360,你可以用一个接近的值替代,例如: 359.99
foreMoveTo | 含义 | 等价方法 |
---|---|---|
true | 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 | public void addArc (RectF oval, float startAngle, float sweepAngle) |
false | 不移动,而是连接最后一个点与圆弧起点 | public void arcTo (RectF oval, float startAngle, float sweepAngle) |
例子(addArc):
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
Path path = new Path();
path.lineTo(100,100); //先画个线
RectF oval = new RectF(0,0,300,300); //确定圆弧的外切矩形的位置
path.addArc(oval,0,270); //在已有的线的基础上添加圆弧
// path.arcTo(oval,0,270,true); // <-- 和上面一句作用等价
canvas.drawPath(path,mPaint);
结果:
例子(arcTo):
canvas.translate(width / 2, height / 2); // 移动坐标系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
Path path = new Path();
path.lineTo(100,100); //先画个线
RectF oval = new RectF(0,0,300,300); //确定圆弧的外切矩形的位置
path.arcTo(oval,0,270); //在已有的线的基础上添加圆弧,不移动,而是连接最后一个点与圆弧起点
// path.arcTo(oval,0,270,false); // <-- 和上面一句作用等价
canvas.drawPath(path,mPaint);
结果:
3. isEmpty 、isRect、 isConvex、 set 、offset
方法: isEmpty
判断path中是否包含内容。
Path path = new Path();
Log.e("1",path.isEmpty()+"");
path.lineTo(100,100);
Log.e("2",path.isEmpty()+"");
结果:
com.sloop.canvas E/1: true
com.sloop.canvas E/2: false
方法:isRect
public boolean isRect (RectF rect)
判断path是否是一个矩形,如果是一个矩形的话,会将矩形的信息存放进参数rect中
path.lineTo(0,400);
path.lineTo(400,400);
path.lineTo(400,0);
path.lineTo(0,0);
RectF rect = new RectF();
boolean b = path.isRect(rect);
Log.e("Rect","isRect:"+b+"| left:"+rect.left+"| top:"+rect.top+"| right:"+rect.right+"| bottom:"+rect.bottom);
结果:
com.sloop.canvas E/Rect: isRect:true| left:0.0| top:0.0| right:400.0| bottom:400.0
方法:set
public void set (Path src)
将新的path赋值到现有path。
canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
Path path = new Path(); // path添加一个矩形
path.addRect(-200,-200,200,200, Path.Direction.CW);
Path src = new Path(); // src添加一个圆
src.addCircle(0,0,100, Path.Direction.CW);
path.set(src); // 大致相当于 path = src;
canvas.drawPath(path,mPaint);
结果:
方法 offset
public void offset (float dx, float dy)
public void offset (float dx, float dy, Path dst)
对path进行一段平移,它和Canvas中的translate作用很像,但Canvas作用于整个画布,而path的offset只作用于当前path。
方法第最后的参数 Path dst 是存储平移后的path的
dst状态 | 效果 |
---|---|
dst不为null | 将当前path平移后的状态存入dst中,不会影响当前path |
dat为空 | 平移将作用于当前path,相当于第一种方法 |
// ====== 方法 offset ========
canvas.translate(width/2 , height / 2); // 移动坐标系到屏幕中心
canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
Path path = new Path(); // path中添加一个圆形(圆心在坐标原点)
path.addCircle(0,0,100, Path.Direction.CW);
Path dst = new Path(); // dst中添加一个矩形
dst.addRect(-200,-200,200,200, Path.Direction.CW);
path.offset(250,0,dst); // 平移
canvas.drawPath(path,mPaint); // 绘制path
mPaint.setColor(Color.BLUE); // 更改画笔颜色
canvas.drawPath(dst,mPaint); // 绘制dst
结果:
平移之前:
平移后:
从运行效果图可以看出,虽然我们在dst中添加了一个矩形,但是并没有表现出来,所以,当dst中存在内容时,dst中原有的内容会被清空,而存放平移后的path。