随笔博文

Android自定义View-Path的详细介绍

2022-12-02 10:55:58 michael007js 277

一、构造方法

1、Path path=new Path();//空的构造方法

2、Path path=new Path(Path src);//创建一个新的路径,并从src路径获取内容赋值给新的路径


二、Path常用的一些方法


分类Path方法备注
点操作moveTo(float x,float y)设置接下来操作的起点位置为(x,y)
rMoveTo(float x,float y)基于当前最后一个点位置移动(x,y)为坐标原点
setLastPoint(float x,float y)改变前面操作中最后点的位置
线操作lineTo(float x,float y)从当前点(上次操作结束的点)到(x,y)画直线
rLineTo(float x,float y)从当前点到移动(x,y)位置的点画直线
常规图形addRect(RecF rect,Path.Direction dir)画矩形
addRect(float left,float top,float right,float bottom,Path.Direction dir)

addRoundRect(RectF rect,float rx,float ry,Path.Direction dir)画圆角矩形radii指定四个角圆角半径,radii要至少8个值(多余的只取前8个)
addRoundRect(float left,float top,float right,float bottom,float rx,float ry,Path.Direction dir)

addRoundRect(RectF rect,float[] radii,Path.Direction dir)

addRoundRect(float left,float top,float right,float bottom,float[] radii,Path.Direction dir)

addArc(RectF oval,float startAngle,float sweepAngle)画弧addArc是直接添加圆弧到path中,arcTo会判断要绘制的圆弧的起点与绘制圆弧前path中最后的点是否是同一个点,如果不是同一个点,并且forceMoveTo=false,就会连接两个点,默认forceMoveTo=false。
addArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle)

arcTo(RectF oval,float startAngle,float sweepAngle,boolean forceMoveTo)

arcTo(RectF oval,float startAngle,float sweepAngle)

arcTo(float left,float top,float right,float bottom,float startAngle,float sweepAngle,boomean forceMoveTo)

addCircle(float x,float y,float radius,Path.Direction dir)画圆
addOval(RectF oval,Path.Direction dir)画椭圆
addOval(float left,float top,float right,float bottom,Path.Direction dir)

添加路径addPath(Path src)将src的路径添加到当前路径
addPath(path src,float x,float y)将src移动(x,y)距离后再添加进当前path
addPath(Path src,Matrix matrix)将src添加到当前路径之前先使用Matrix进行变换
闭合close如果连接Path起点和终点能形成一个闭合图形,则会将起点和终点连接起来形成一个闭合图形。
贝塞尔曲线quadTo(float x1,float y1,float x2,float y2)绘制二阶贝塞尔曲线(x1,y1)为控制点,(x2,y2)为终点
rQuadTo(float x1,float y1,float x2,float y2)绘制二阶贝塞尔曲线(x1,y1)为控制点距离起点的偏移量(x2,y2)为终点距离起点的偏移量
cubicTo(float x1,float y1,float x2,float y2,float x3,float y3)绘制三阶贝塞尔曲线(x1,y1)(x2,y2)为控制点(x3,y3)为终点
rCubicTo(float x1,float y1,float x2,float y2,float x3,float y3)绘制三阶贝塞尔曲线(x1,y1)(x2,y2)为控制点距离起点的偏移量(x3,y3)为终点距离起点的偏移量
是否为矩形isRect()判断Path是否是一个矩形
是否为空isEmpty()判断Path是否为空
替换路径set(Path src)用新的路径src替换当前路径的所有内容
平移路径对Path进行一段平移(和Canvas的translate相似,translate作用于整个画布,offset作用于当前path)offset(float dx,float dy)将当前path平移(x,y)
offset(float dx,float dy,Path dst)将当前path平移后的状态存入dst中,不会影响当前pathdst为null则会将平移作用于当前path
填充模式setFillType(Path.FillType ft)设置填充方式WINDING:非零环绕数规则INVERSE_WINDING:反非零环绕数规则EVEN_ODD:奇偶规则INVERSE_ODD:反奇偶规则
getFillType()获取填充模式
isInverseFillType()判断是否是反向填充方式
toggleInverseFillType()切换填充模式(原有规则与反向规则之间相互切换)
布尔操作op(Path path1,Path.Op op)对当前路径和path1路径执行布尔运算,运算方式有第二个参数指定,运算结果存入当前路径
op(Path path1,Path path2,Path.Op op)对path1和path2执行布尔运算,运算方式由第三个参数指定,运算结果存入当前路径



1、点操作

1)moveTo和rMoveTo

        mPaint.setColor(Color.RED);
       //将起点移动到(100,100)位置
       mPath.moveTo(100,100);
       mPath.lineTo(200, 200);
       //将起点移动到(400,400)位置
       mPath.rMoveTo(200,200);
       mPath.lineTo(600,600);
       canvas.drawPath(mPath,mPaint);

效果显示为:

img

2)moveTo、rMoveTo改变后面操作的起始点位置,setLastPoint改变前面操作中最后点的位置

moveTo:

        mPaint.setColor(Color.RED);
       mPath.lineTo(200, 0);
       //将起点设置为(100,100)
       mPath.moveTo(100, 100);
       mPath.lineTo(200, 200);
       mPath.lineTo(0,200);
       mPath.close();
       canvas.drawPath(mPath, mPaint);

显示效果是:

img

setLastPoint():

将上边的mPath.moveTo(100,100)换成mPath.setLastPoint(100,100)

        mPaint.setColor(Color.RED);
       mPath.lineTo(200, 0);
       //改变前面操作中最后点的位置,即将(200,0)改成(100,100)
       mPath.setLastPoint(100,100);
       mPath.lineTo(200, 200);
       mPath.lineTo(0,200);
       mPath.close();
       canvas.drawPath(mPath, mPaint);

显示效果是:

img

moveTo和setLastPoint的区别:


方法名作用是否影响之前的操作是否影响起点
moveTo移动下一次操作的起点位置
setLastPoint设置之前操作的最后一个点位置


2、线操作

        mPaint.setColor(Color.RED);
       mPath.lineTo(200, 400);
       mPath.lineTo(400,600);
       //画(400,600)到(800,1200)位置的线
       mPath.rLineTo(400,600);
       canvas.drawPath(mPath,mPaint);

效果图

img

3、常规图形

1)addArc和arcTo

forceMoveTo=true

        mPaint.setColor(Color.RED);
       RectF rectF1=new RectF(0,0,200,200);
       mPath.addArc(rectF1,90,90);
       RectF rectF2=new RectF(200,200,400,400);
       mPath.arcTo(rectF2,0,90,true);

显示效果:

img

forceMoveTo=false 或者不设置

        mPaint.setColor(Color.RED);
       RectF rectF1=new RectF(0,0,200,200);
       mPath.addArc(rectF1,90,90);
       RectF rectF2=new RectF(200,200,400,400);
       mPath.arcTo(rectF2,0,90,false);
       //或者mPath.arcTo(rectF2,0,90);
       canvas.drawPath(mPath,mPaint);

显示效果:

img

2)Path.Direction参数的作用:

点进去Direction,发现是一个枚举类型,里面只有两个枚举常量

CW:沿顺时针方向绘制

CCW:沿逆时针方向绘制

CW:

        mPath.addCircle(0,0,300,Path.Direction.CW);
       mPaint.setTextSize(30);
       canvas.drawTextOnPath("唯一纯白的茉莉花,盛开在琥珀色月牙,就算失去所有爱的力量,我也不会害怕",mPath,0,0,mPaint);
       canvas.drawPath(mPath,mPaint);

显示效果:

img

设置为CW时,path画圆的时候按照顺时针方向,所以文字也是按顺时针方向显示。

CCW:

        mPath.addCircle(0,0,300,Path.Direction.CCW);
       mPaint.setTextSize(40);
       canvas.drawTextOnPath("唯一纯白的茉莉花,盛开在琥珀色月牙,就算失去所有爱的力量,我也不会害怕",mPath,0,0,mPaint);
       canvas.drawPath(mPath,mPaint);

显示效果:

img

设置为CCW时,path画圆的时候按照逆时针方向,所以文字也是按逆时针方向显示。

CW:

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

显示效果:

img

设置为CW顺时针方向的时候,绘制矩形是从起始位置(-200,-200)到(-200,200)画矩形,这个时候设置setLastPoint(-100,100),也就是原来(-200,200)的位置被(-100,100)代替了。

CCW:

        mPath.addRect(-200,-200,200,200,Path.Direction.CCW);
        mPath.setLastPoint(-100,100);
        canvas.drawPath(mPath,mPaint);

显示效果:

img

设置为CCW逆时针方向的时候,绘制矩形是从起始位置(-200,-200)到(200,-200)画矩形,这个时候设置setLastPoint(-100,100),也就是原来(200,-200)的位置被(-100,100)代替了。

4、添加路径

addPath(Path src,float x,float y):

        Path src = new Path();
        src.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.addPath(src, 0, 100);
        canvas.drawPath(mPath,mPaint);

显示效果:

img

5、替换路径

        Path src = new Path();
        src.addCircle(200, 0, 100, Path.Direction.CW);
        mPath.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.set(src);
        canvas.drawPath(mPath, mPaint);

显示效果:

img

6、偏移路径

1)offset(float dx,float dy)

        mPath.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.offset(0, 200);
        canvas.drawPath(mPath, mPaint);

显示效果:

img

2)offset(float dx,float dy,Path dst)

        Path dst = new Path();
        mPath.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.offset(0, 200, dst);
        canvas.drawPath(mPath, mPaint);
        mPaint.setColor(Color.GREEN);
        canvas.drawPath(dst, mPaint);

显示效果:

img

7、填充模式

在Path中,有四种填充模式:


填充模式备注
WINDING非零环绕数规则
INVERSE_WINDING反非零环绕数规则
EVEN_ODD奇偶规则
INVERSE_WINDING反奇偶规则


WINDING:

非零环绕原则:首先,它需要你图形中的所有线条都是有绘制方向的:

img

然后,从平面中的点向任意方向射出一条射线,以0为初始值,对于射线和图形的所有交点,每遇到顺时针的交点,把结果加1,每遇到逆时针的交点,把结果减1,最终把所有的交点都算上,得到的结果如果不是0,则认为这个点在图形内部,是要被

涂色的区域;如果是0,则认为这个点在图形外部,是不被涂色的区域。

img

EVEN_ODD:

奇偶原则,对于平面中的任意一点,向任意方向射出一条射线,这条射线和图形相交的次数(必须是相交,相切不算)如果是奇数,则这个点被认为在图形内部,是要被涂色的区域;如果是偶数,则这个点被认为在图形外部,是不被涂色的区域。

img

INVERSE_WINDING和INVERSE_ODD只是把两种效果进行反转。

几个效果图:

img


8、布尔运算

布尔运算可以指定不同的布尔操作方式:


参数备注
DIFFERENCEpath1不同于path2的区域
REVERSEDIFFERENCEpath2不同于path1的区域
INTERSECTpath1与path2相交区域
UNIONpath1与path2的和
XORpath1与path2和并减去重叠的部分


DIFFERENCE:

        Path path1 = new Path();
        path1.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.addCircle(0, 50, 100, Path.Direction.CW);
        mPath.op(path1, Path.Op.DIFFERENCE);
        canvas.drawPath(mPath, mPaint);

显示效果:

img

REVERSEDIFFERENCE:

        Path path1 = new Path();
        path1.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.addCircle(0, 50, 100, Path.Direction.CW);
        mPath.op(path1, Path.Op.REVERSE_DIFFERENCE);
        canvas.drawPath(mPath, mPaint);

显示效果:

img

INTERSECT:

        Path path1 = new Path();
        path1.addCircle(0, 0, 100, Path.Direction.CW);
        mPath.addCircle(0, 50, 100, Path.Direction.CW);
        mPath.op(path1, Path.Op.INTERSECT);
        canvas.drawPath(mPath, mPaint);

显示效果:

img

UNION:

        Path path1 = new Path();
       path1.addCircle(0, 0, 100, Path.Direction.CW);
       mPath.addCircle(0, 50, 100, Path.Direction.CW);
       mPath.op(path1, Path.Op.UNION);
       canvas.drawPath(mPath, mPaint);

显示效果:

img

XOR:

      Path path1 = new Path();
     path1.addCircle(0, 0, 100, Path.Direction.CW);
     mPath.addCircle(0, 50, 100, Path.Direction.CW);
     mPath.op(path1, Path.Op.XOR);
     canvas.drawPath(mPath, mPaint);

显示效果:

img



首页
关于博主
我的博客
搜索