Android开发之Path详解

目录

    • 一、xxxTo方法
      • 1、lineTo(float x, float y)
      • 2、moveTo(float x, float y)
      • 3、arcTo
        • 3.1、arcTo(RectF oval, float startAngle, float sweepAngle)
        • 3.2、arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
        • 3.3、arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)
      • 4、quadTo(float x1, float y1, float x2, float y2)
      • 5、cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
    • 二、rXxxTo方法
    • 三、addXxx方法
      • 1、addArc(RectF oval, float startAngle, float sweepAngle)
      • 2、addCircle(float x, float y, float radius, Direction dir)
      • 3、addOval(RectF oval, Direction dir)
      • 4、addRect(RectF rect, Direction dir)
      • 5、addRoundRect
        • 5.1、addRoundRect(RectF rect, float rx, float ry, Direction dir)
        • 5.2、addRoundRect(RectF rect, float[] radii, Direction dir)
      • 6、addPath(Path src)
        • 6.1、addPath(Path src, float dx, float dy)
        • 6.2、addPath(Path src, Matrix matrix)
    • 四、填充模式
    • 五、其他方法
      • 1、op(Path path, Op op) 布尔运算
        • 1.1、DIFFERENCE(差集)
        • 1.2、REVERSE_DIFFERENCE(差集)
        • 1.3、INTERSECT(交集)
        • 1.4、UNION(并集)
        • 1.5、XOR(异或)
      • 2、setLastPoint(float dx, float dy)

一、xxxTo方法

Path类中提供了一套xxxTo方法,其作用是从起点到终点移动path画笔并绘制线(moveTo方法只移动path画笔不绘制线),线有直线和曲线
方法汇总如下表所示:

方法名参数解析
lineTo(float x, float y)绘制直线,x:终点x坐标值,y:终点y坐标值
moveTo(float x, float y)移动画笔,x:终点x坐标值,y:终点y坐标值
arcTo(RectF oval, float startAngle, float sweepAngle)绘制圆弧,oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)绘制圆弧,oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度,forceMoveTo:是否在绘制圆弧前移动(moveTo)path画笔位置
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)绘制圆弧,left、top、right、bottom组成圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度,forceMoveTo:是否在绘制圆弧前移动(moveTo)path画笔位置
quadTo(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)绘制三阶贝塞尔曲线,其中控制点1坐标为(x1,y1),控制点2坐标为(x2,y2),终点坐标为(x3,y3)

1、lineTo(float x, float y)

绘制直线:从当前画笔位置出发,连接终点(x,y)。

示例如下:

path.lineTo(300,300);
canvas.drawPath(path,paint);

在这里插入图片描述

2、moveTo(float x, float y)

移动画笔:从当前画笔位置移动到终点(x,y)

示例如下:

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path,paint);

在这里插入图片描述

3、arcTo

3.1、arcTo(RectF oval, float startAngle, float sweepAngle)

绘制圆弧:从当前画笔位置出发,连线到内切矩形区域oval的圆弧的起始角度startAngle位置(X轴正方向为0°),顺时针旋转绘制圆弧,旋转度数为sweepAngle(sweepAngle为负时则逆时针旋转)

示例如下:

RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180);
canvas.drawPath(path,pathPaint);

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

绘制圆弧:forceMoveTofalse,则用法和arcTo(RectF oval, float startAngle, float sweepAngle)一样,绘制圆弧之前不会移动(moveTo)path画笔位置。若为true,先强制调用moveTo移动path画笔至圆弧起点,再绘制圆弧。PS:如果调用arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)方法之前没有对path进行任何操作,则forceMoveTo设置true或false效果都和设置true一样

示例如下,注意对比之间的差异:

RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);

在这里插入图片描述

RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,true);
path.close();
canvas.drawPath(path,pathPaint);

在这里插入图片描述

RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);

在这里插入图片描述

3.3、arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

绘制圆弧:与arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)用法一样

4、quadTo(float x1, float y1, float x2, float y2)

绘制二阶贝塞尔曲线:从path画笔当前位置出发,以(x₁,y₁)为控制点,向终点(x₂,y₂)绘制一条二阶贝塞尔曲线

示例如下:

path.moveTo(100,100);
path.quadTo(200,0,400,100);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

5、cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

绘制三阶贝塞尔曲线:从path画笔当前位置出发,以(x1,y1)为控制点1,以(x2,y2)为控制点2,向终点(x3,y3)绘制一条三阶贝塞尔曲线

示例如下:

path.moveTo(100,100);
path.cubicTo(200,0,300,90,500,100);
canvas.drawPath(path,pathPaint);

在这里插入图片描述
圆形其实也是由四段三阶贝塞尔曲线组成,我们绘制其中两段看看效果即可,示例如下:

path.moveTo(300,200);
path.cubicTo(300,200+100*0.551915024494f,200+100*0.551915024494f,300,200,300);path.moveTo(200-20,300);
path.cubicTo(200-100*0.551915024494f-20,300,100-20,200+100*0.551915024494f,100-20,200);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

二、rXxxTo方法

在这里插入图片描述
rXxxTo方法的r意思是relative,即相对的意思,方法有四个,如上图所示,其功能与对应的xxxTo方法一样,区别在于rXxxTo方法在绘制Path时是以当前path画笔位置为坐标原点,即相对于path画笔位置进行绘制,而xxxTo方法的坐标原点则与当前canvas坐标原点一致。

例如,我们使用xxxTo方法:

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path, pathPaint);

上述代码是从(100,100)到(300,300)绘制一条直线,那么如果用rXxxTo方法,相对(100,100)这个点绘制直线,则终点应为(300-100,300-100),即终点设为(200,200),如下所示:

path.moveTo(100,100);
path.rLineTo(200,200);
canvas.drawPath(path, pathPaint);

效果都是一样的:
在这里插入图片描述

三、addXxx方法

Path类中还提供了一套addXxx方法,字面理解就是添加一段相应的线,线可以是曲线完整的圆形矩形等,甚至可以是另一组Path的线。所谓添加的意思,我个人理解就是在绘制这段线前,移动(moveTo)path画笔位置到线的起始位置,然后再绘制线,也就是说添加的这段线,与之前绘制的Path是分离的(除非后绘制的这段线的起始点与之前Path的终点一致)

方法汇总如下表所示:

方法名参数解析
addArc(RectF oval, float startAngle, float sweepAngle)添加圆弧,oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)添加圆弧,left、top、right、bottom组成圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度。ps:此方法在API 19以上有效
addCircle(float x, float y, float radius, Direction dir)添加圆形,x:圆形圆心的x坐标,y:圆形圆心的y坐标,radius:圆形半径,dir:线的闭合方向(CW顺时针方向
addOval(RectF oval, Direction dir)添加椭圆,oval:椭圆内切的矩形区域,dir:线的闭合方向(CW顺时针方向
addOval(float left, float top, float right, float bottom, Direction dir)添加椭圆,left、top、right、bottom组成椭圆内切的矩形区域,dir:线的闭合方向(CW顺时针方向
addRect(RectF rect, Direction dir)添加矩形,rect:矩形区域,dir:线的闭合方向(CW顺时针方向
addRect(float left, float top, float right, float bottom, Direction dir)添加矩形,left、top、right、bottom组成矩形区域,dir:线的闭合方向(CW顺时针方向
addRoundRect(RectF rect, float rx, float ry, Direction dir)添加统一圆角的圆角矩形,rect:矩形区域,rx:椭圆圆角的横轴半径,ry:椭圆圆角的纵轴半径,dir:线的闭合方向(CW顺时针方向
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)添加统一圆角的圆角矩形,left、top、right、bottom组成矩形区域,rx:椭圆圆角的横轴半径,ry:椭圆圆角的纵轴半径,dir:线的闭合方向(CW顺时针方向
addRoundRect(RectF rect, float[] radii, Direction dir)添加非统一圆角的圆角矩形,rect:矩形区域,radii:矩形四个椭圆圆角的横轴半径和纵轴半径的数组,一共8个数值,dir:线的闭合方向(CW顺时针方向
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)添加非统一圆角的圆角矩形,left、top、right、bottom组成矩形区域,radii:矩形四个椭圆圆角的横轴半径和纵轴半径的数组,一共8个数值,dir:线的闭合方向(CW顺时针方向
addPath(Path src)添加一组Path,src:要添加的Path
addPath(Path src, float dx, float dy)添加一组平移后的Path,src:要添加的Path,dx:平移的x坐标,dy:平移的y坐标
addPath(Path src, Matrix matrix)添加一组经过矩阵变换后的Path,src:要添加的Path,matrix:3x3的矩阵

1、addArc(RectF oval, float startAngle, float sweepAngle)

添加圆弧:addArc两个方法使用起来与arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)中forceMoveTo设置为true效果一致,就不展开赘述了

2、addCircle(float x, float y, float radius, Direction dir)

添加圆形:以点(x,y)为圆心,添加一个半径长为radius的圆形,绘制起始角度为0°(x轴方向),绘制方向通过dir的值而定,dir为CW时顺时针绘制,dir为CCW时逆时针绘制。

方法比较简单,主要是对比CW和CCW的区别,我们用canvas.drawTextOnPath方法突显顺时针和逆时针绘制的效果,示例如下:

path.addCircle(200,150,100, Path.Direction.CW);//顺时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

path.addCircle(200,150,100, Path.Direction.CCW);//逆时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

3、addOval(RectF oval, Direction dir)

添加椭圆:在oval矩形区域中,添加一个内切的椭圆,绘制起始角度为0°(x轴方向),绘制方向通过dir的值而定,dir为CW时顺时针绘制,dir为CCW时逆时针绘制。

注: addOval(RectF oval, Direction dir)和addOval(float left, float top, float right, float bottom, Direction dir)效果是一样的,就不分开讲了。

示例如下:

RectF rectF = new RectF(100,100,400,250);
path.addOval(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

4、addRect(RectF rect, Direction dir)

添加矩形:添加一个区域为rect的矩形,绘制起点为左上角,绘制方向通过dir的值而定,dir为CW时顺时针绘制,dir为CCW时逆时针绘制。

注: addRect(RectF rect, Direction dir)和addRect(float left, float top, float right, float bottom, Direction dir)效果是一样的,就不分开讲了

示例如下:

RectF rectF = new RectF(100,100,400,250);
path.addRect(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

5、addRoundRect

5.1、addRoundRect(RectF rect, float rx, float ry, Direction dir)

添加统一圆角的圆角矩形:添加一个区域为rect的圆角矩形,四个角的圆角大小一致,圆角的横轴半径为rx,纵轴半径为ry,dir为CW时顺时针绘制,绘制起点为左下角,dir为CCW时逆时针绘制,绘制起点为左上角(注意对比顺时针和逆时针的绘制起点)。

注: addRoundRect(RectF rect, float rx, float ry, Direction dir)和addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)效果是一样的,就不分开讲了。

示例如下:

RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CW);//顺时针
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CCW);//逆时针
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

5.2、addRoundRect(RectF rect, float[] radii, Direction dir)

添加非统一圆角的圆角矩形:添加一个区域为rect的圆角矩形,四个角的圆角的横轴和纵轴半径由radii数组中的8个数值决定,dir为CW时顺时针绘制,绘制起点为左下角,dir为CCW时逆时针绘制,绘制起点为左上角(注意对比顺时针和逆时针的绘制起点)。

注: 需要注意的是,如果radii数组中的元素小于8,系统会抛出错误信息radii[] needs 8 values,如下图所示:
在这里插入图片描述
在这里插入图片描述
注: addRoundRect(RectF rect, float[] radii, Direction dir)和addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)效果是一样的,就不分开讲了。

RectF rectF = new RectF(100,100,400,350);
float[] radii = {60,30,30,70,100,100,10,40};
path.addRoundRect(rectF,radii,Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

在这里插入图片描述

6、addPath(Path src)

添加一组名为src的Path副本

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

6.1、addPath(Path src, float dx, float dy)

添加一组名为src的Path副本,然后将其进行平移,x轴上的平移距离为dx,y轴上的平移距离为dy

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath,300,0);//向x轴正方向平移300像素距离
canvas.drawPath(path,pathPaint);

在这里插入图片描述

6.2、addPath(Path src, Matrix matrix)

添加一组名为src的Path副本,然后将其进行矩阵变换,矩阵为matrix(3x3的矩阵)

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();Matrix mMatrix = new Matrix();
mMatrix.setScale(1,-1);//以x轴为中线进行翻转
mMatrix.postRotate(90);//以坐标轴原点为中心点顺时针旋转90°path.addPath(copyPath,mMatrix);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

四、填充模式

方法名参数解析
setFillType(FillType ft)设置Path的填充模式,ft:填充类型,有EVEN_ODD ,INVERSE_EVEN_ODD ,WINDING ,INVERSE_WINDING 四种模式
getFillType()获取当前Path的填充模式
isInverseFillType()判断当前Path填充模式是否是反向规则(INVERSE_XXX)
toggleInverseFillType()当前Path的填充模式与其反向规则模式进行相互切换

五、其他方法

方法名参数解析
close()封闭当前Path,连接起点和终点
reset()清空Path中的所有直线和曲线,保留填充模式设置,不保留Path上相关的数据结构
rewind()清空Path中的所有直线和曲线,不保留填充模式设置,但会保留Path上相关的数据结构,以便高效地复用
set(Path src)用名为src的Path替换当前的Path
op(Path path, Op op)当前Path与名为path的Path进行布尔运算(取差集、交集、并集等),op:运算逻辑,有DIFFERENCE(差集),REVERSE_DIFFERENCE(差集),INTERSECT(交集),UNION(并集),XOR(异或)五种运算逻辑可选。ps:此方法在API 19以上有效
offset(float dx, float dy)平移当前Path,x轴上平移的距离为dx,y轴上平移的距离为dy
offset(float dx, float dy, Path dst)平移名为dst的Path,x轴上平移的距离为dx,y轴上平移的距离为dy
transform(Matrix matrix)对当前Path进行矩阵变换,矩阵为matrix(3x3矩阵)
transform(Matrix matrix, Path dst)对名为dst的Path进行矩阵变换,矩阵为matrix(3x3矩阵)
setLastPoint(float dx, float dy)设置终点,设置当前Path最后一个点的位置为(dx,dy)
isEmpty()判断当前Path是否为空
isConvex()判断当前Path围成的图形是否凸多边形。ps:此方法在API 21以上有效
isRect(RectF rect)判断当前Path是否为矩形,如是,则将当前Path存储到新建的rect中

注: 这里大多数方法都比较简单,有些之前已经应用过,就不展开来讲了,下面介绍一下其中比较特别且常用的几个方法。

1、op(Path path, Op op) 布尔运算

前面的表格我们提到参数op共有五种运算逻辑可选,下面我们就来看看这五种运算逻辑是如何影响两个Path之间的关系的,我们先用不同的颜色绘制出一个矩形和一个圆形,观察一下它们的位置和关系:

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path1,pathPaint);Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);
pathPaint.setColor(Color.RED);
canvas.drawPath(path2,pathPaint);

在这里插入图片描述
下面我们对这两个Path进行布尔运算:

1.1、DIFFERENCE(差集)

若op方法的调用关系为path1.op(path2, Path.Op.DIFFERENCE),则运算结果是path1减去与path2的交集后剩下的部分,即path1与path2的并集减去path2部分

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path1.op(path2, Path.Op.DIFFERENCE);//path1与path2进行布尔运算,结果保存至path1canvas.drawPath(path1,pathPaint);
}//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path3.op(path1,path2,Path.Op.DIFFERENCE);//path1与path2进行布尔运算,结果保存至path3canvas.drawPath(path3,pathPaint);
}

可以用path1.op直接运算,也可以新建一个path3保存path1和path2的运算结果,效果都是一样的
在这里插入图片描述

1.2、REVERSE_DIFFERENCE(差集)

若op方法的调用关系为path1.op(path2, Path.Op.REVERSE_DIFFERENCE),则运算结果是path2减去与path1的交集后剩下的部分,即path1与path2的并集减去path1部分

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path1.op(path2, Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算,结果保存至path1canvas.drawPath(path1,pathPaint);
}//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path3.op(path1,path2,Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算,结果保存至path3canvas.drawPath(path3,pathPaint);
}

在这里插入图片描述

1.3、INTERSECT(交集)

若op方法的调用关系为path1.op(path2, Path.Op.INTERSECT),则运算结果是path1与path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path1.op(path2, Path.Op.INTERSECT);//path1与path2进行布尔运算,结果保存至path1canvas.drawPath(path1,pathPaint);
}//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path3.op(path1,path2,Path.Op.INTERSECT);//path1与path2进行布尔运算,结果保存至path3canvas.drawPath(path3,pathPaint);
}

在这里插入图片描述

1.4、UNION(并集)

若op方法的调用关系为path1.op(path2, Path.Op.UNION),则运算结果是path1与path2的并集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path1.op(path2, Path.Op.UNION);//path1与path2进行布尔运算,结果保存至path1canvas.drawPath(path1,pathPaint);
}//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path3.op(path1,path2,Path.Op.UNION);//path1与path2进行布尔运算,结果保存至path3canvas.drawPath(path3,pathPaint);
}

在这里插入图片描述

1.5、XOR(异或)

若op方法的调用关系为path1.op(path2, Path.Op.XOR),则运算结果是path1与path2的并集减去path1与path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path1.op(path2, Path.Op.XOR);//path1与path2进行布尔运算,结果保存至path1canvas.drawPath(path1,pathPaint);
}//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {path3.op(path1,path2,Path.Op.XOR);//path1与path2进行布尔运算,结果保存至path3canvas.drawPath(path3,pathPaint);
}

在这里插入图片描述

2、setLastPoint(float dx, float dy)

当Path在调用setLastPoint方法之前执行了某项操作时(绘制直线或曲线等),会将该操作的终点强制设置为(dx,dy)并连线(线的曲直取决于该操作本身是绘制直线还是曲线)

理解这个方法之前,首先我们要知道无论是使用addXxx方法还是xxxTo方法等在绘制过程中其实都是根据一堆点的集合,按顺序连线(直线或曲线)后绘制出Path最终的样子,setLastPoint方法正是改变此方法调用之前点的集合中最后一个点的位置。下面我们通过封闭图形(矩形)和非封闭图形(一段圆弧)的例子更好地理解这个方法。

//用绿线绘制一个矩形
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);//强制设置最后一个点为(150,250),用红线绘制观察变化
path.reset();
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
path.setLastPoint(150,250);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

//用绿线绘制一个旋转180°的圆弧
path.addArc(new RectF(100,100,300,300),0,180);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);//强制设置最后一个点为(200,200),用红线绘制观察变化
path.reset();
path.addArc(new RectF(100,100,300,300),0,180);
path.setLastPoint(200,200);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android APK打包流程

目录一、概述二、打包流程1、打包资源文件,生成R.java文件2、处理aidl文件,生成相应的Java文件3、编译项目源代码,生成class文件4、转换所有的class文件,生成classes.dex文件5、打包生成APK文件6、对APK文件进行签名7、对签名后的…

Android Studio 安装ASM插件

目录一、安装步骤1、Android Studio -> Preferences...2、Plugins -> Browse repositories...3、搜索ASM -> 选中要安装的插件 -> 右侧点击Install4、安装完后点击Restart Android Studio5、Android Studio重启后右侧会有个ASM图标6、找一个类右键 -> Show Byte…

使用openssl完成aes-cbc模式的数据加解密,输入和输出都是字符串的形式

代码 #include <cstring> #include <memory>#include <openssl/aes.h> #include <openssl/md5.h>namespace hsm{namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]){MD5_CTX md5_ctx{};MD5_Init(&md5_ctx);MD5…

Android ViewRoot、DecorViewWindow浅析

目录简介目录1、VeiwRoot1.1、简介1.2、特别注意2、DecorView2.1、定义2.2、作用2.3、特别说明3、Window4、Activity5、之间关系5.1、总结5.2、之间的关系简介 DecorView为整个Window界面的最顶层View。DecorView只有一个子元素为LinearLayout。代表整个Window界面&#xff0c;…

Android 为控件设置阴影

在Android中设置一个阴影很简单&#xff0c;只需要两步&#xff1a; 设置eleavation值&#xff08;高度&#xff09;添加一个背景或者outline &#xff08;即阴影的形状&#xff09; 说明&#xff1a; View的大小位置都是通过x&#xff0c;y确定的&#xff0c;而现在有了z轴的…

Android学习指南

目录核心分析内容1、学什么1.1、Android基础 & 常用1.2、Android进阶1.3、与时俱进、热门技术1.4、编程语言&#xff1a;Java与Java虚拟机1.5、计算机基础1.6、总结2、怎么学2.1、学习路径&#xff1a;如何循序渐进、阶段性的学习Android的理论知识&#xff1f;2.2、获取途…

概率论 事件关系 古典概型与几何概型

基本知识点 随机试验:1.不确定性2.可预知性3.可重复性基本事件:包含一个样本点 必然事件:全集 不可能事件:空集 子集2^n-1-1(减去空集与真集) 事件间的关系 1.包含关系 2.和运算AUBAB,A与B至少有一个发生 3.积事件A∩BAB,AB同时发生 4.差事件A-BAB ̅A-AB,A发生但B不发生 5.…

Android代码命名规范

目录目录1、为什么 规范 Android 代码命名&#xff1f;2、Android需要命名的代码&#xff08;对象&#xff09;有哪些&#xff1f;3、具体命名规范3.1、包3.2、类3.3、变量3.4、方法3.5、参数名3.6、资源3.6.1、布局文件资源3.6.2、图片资源3.6.3、参数值资源3.6.4、动画资源3.…

Idea中搭建Resin运行环境(Mac)

一、背景 idea中搭建Resin运行环境&#xff0c;可以在idea中通过点击Run按钮直接调试应用。 二、Resin下载地址 下载地址&#xff1a;https://caucho.com/products/resin/download/gpl#download 我下载的是tar.gz的&#xff0c;通过tar -zxvf命令解压到自己mac的任意目录下…

Java牛客专项练习2020.12.10

TreeSet subset()方法: subset(from,true,to,true),返回从from元素到to元素的一个集合,true判断是否包含边境元素 Java与C Java与C都有三个特征: 封装,继承,多态 抽象类与接口 1.抽象类可以有构造方法,但不能new;接口没有构造方法 2.抽象类中可以有普通成员变量int x等,接…

Idea中搭建Wildfly(JBoss)运行环境(Mac)

目录一、简介二、下载Wildfly&#xff08;JBoss&#xff09;三、配置Idea四、调试一、简介 首先说一下在linux环境&#xff0c;只需要将war包上传到 wildfly-8.2.0.Final/standalone/deployments 目录&#xff0c;然后到 wildfly-8.2.0.Final/bin 目录下 ./standalone.sh&…

一个简单JavaAgent的实现

一、什么是javaagent javaagent是一个JVM“插件”&#xff0c;一种专门精心制作的.jar文件&#xff0c;它能够利用JVM提供的Instrumentation API。 1.1、概要 Java Agent由三部分组成&#xff1a;代理类、代理类元信息和JVM加载.jar和代理的机制&#xff0c;整体内容如下图所…

Openai的openai新版本调用方式

最近大家有没有发现Openai的openai已经更新到1.6.1了,而且API的调用方式发生了巨大的变化,下面来看看openai新的调用方式吧。 欢迎关注公众号 module ‘openai’ has no attribute ChatCompletion. 提示openai的版本过低。(pip install -U openai) 1. Chat API from openai…

计算机系统基础 计算机系统的基本组成与基本功能

基础知识点 1.1946年第一台通用电子计算机ENIAC诞生 2.冯.诺依曼结构: 组成:输入设备,输出设备,存储器,运算器,控制器 3.现代计算机结构模型: 组成 CPU中央处理器 PC程序计数器 IR指令寄存器 ALU算数逻辑部件 GPRs通用寄存器组 MAR存储器地址寄存器 MDR存储器数据寄存器 知…

Android UI卡顿监控

一、背景 应用的使用流畅度&#xff0c;是衡量用户体验的重要标准之一。Android 由于机型配置和系统的不同&#xff0c;项目复杂App场景丰富&#xff0c;代码多人参与迭代历史较久&#xff0c;代码可能会存在很多UI线程耗时的操作&#xff0c;实际测试时候也会偶尔发现某些业务…

物理 质点运动学

常用公式 重点 1.求轨道方程:消去时间t 2.dr---->位置矢量大小的增量 3.求方向:tanax/y 4.求位置也就是求位移rxiyj即可 习题解析 1.求运动时一定要求出加速度,变速与匀速就是看a 2.求位移时必须看X0是不是为0,如果不为0,求位移与路程时都要减去x0 3. 记住等号两边统一…

使用CLion的时候,对于cmake的使用

问题概述 使用CLion的时候&#xff0c;一个大的项目会有一个总的CMakeLists.txt&#xff0c;这个是控制整个项目的编译环境&#xff0c;但是针对测试的代码会有自己的单独的CMakeLists.txt&#xff0c;这个单独的cmake文件是控制自己的程序所需要的环境即使是编译单独的测试程…

Android NDK之静态/动态注册Native方法

一、简介 关于NDK有两种方法注册&#xff1a;静态注册和动态注册。 静态注册&#xff1a; 就是直接在Java文件里写个native方法 然后再c/c文件中实现这个方法就行了&#xff1b;动态注册&#xff1a; 就是为了不要写很长的方法名&#xff0c;用JNI_OnLoad方法实现预注册&…

概率论 条件概率 全概率 贝叶斯公式

常用知识点 条件概率 1.P(B|A)1表示A发生的情况下B必然发生 A属于B 2.可列可加性 P(BUC|A)P(B|A)P(C|A) 3.P(B|A)的样本空间为A,A与B都发生了 大题解答思路 1.首先设取出一件商品为次品为事件A 2.写B1:甲生产,B2:乙生产 PB1…PB2… P(A|B1)…P(A|B2)… 3.写PAPB1*P(A|B1)……