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.pswp.cn/news/446930.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446930.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446930.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

git大文件拷貝代碼命令

git clone 鏈接 --recursive

Android APK打包流程

目錄一、概述二、打包流程1、打包資源文件,生成R.java文件2、處理aidl文件,生成相應的Java文件3、編譯項目源代碼,生成class文件4、轉換所有的class文件,生成classes.dex文件5、打包生成APK文件6、對APK文件進行簽名7、對簽名后的…

使用openssl,實現輸入和輸出都是字符串的類型,注意:輸入最好是16的倍數

頭文件crypto_util.h #pragma once#include <string>namespace hsm{namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]);std::string aes_encrypt_to_string(const std::string &string,const std::string &password);std::s…

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 網絡異常

目錄前言一、UnknownHostException1、網絡斷開驗證2、DNS 服務器意外掛掉驗證3、DNS 服務器故障驗證4、所需診斷信息二、ConnectTimeoutException三、SocketTimeoutException1、子錯誤 - 讀超時2、子錯誤 - SSL 握手超時3、子錯誤 - 未知原因四、HttpHostConnectException1、服…

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;…

Java集合Stream類

Java集合Stream類 ----按條件對集合進行過濾filter public class Test {public static void main(String[] args) {List<String>allnew ArrayList<>();all.add("ghjt");all.add("ghjiiii");Stream<String>streamall.stream();List<S…

使用openssl完成aes-ecb模式的數據加解密,輸入和輸出都是字符串類型

代碼 #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…

Java Stream MapReduce大數據開發模型

實現一個購買商品后,對數據進行處理統計的功能. 將購買的商品信息保存在Orders類中 public class Orders {private String name;private double price;private int amount;public Orders(String name, double price, int amount) {this.name name;this.price price;this.am…

隨機函數的生成

函數代碼 #include <string>bool GenerateRandom(std::string *str,unsigned int len) {srand(time(NULL));for(unsigned int i0;i<len;i){switch(rand()%3){case 1:(*str).push_back(Arand()%26);break;case 2:(*str).push_back(arand()%26);break;default:(*str).p…

Android 為控件設置陰影

在Android中設置一個陰影很簡單&#xff0c;只需要兩步&#xff1a; 設置eleavation值&#xff08;高度&#xff09;添加一個背景或者outline &#xff08;即陰影的形狀&#xff09; 說明&#xff1a; View的大小位置都是通過x&#xff0c;y確定的&#xff0c;而現在有了z軸的…

Android在代碼中設置drawableLeft(Right/Top/Bottom)

根據業務的需要&#xff0c;要在代碼中設置控件的drawableLeft&#xff0c;drawableRight&#xff0c;drawableTop&#xff0c;drawableBottom屬性。 我們知道在xml中設置的方法為&#xff1a; android:drawableLeft"drawable/xxxxx"但是在代碼中并沒有相關的setDr…

Java 冒泡排序

冒泡排序–時間復雜度n^2 對數組序列從前向后依次比較相鄰兩個元素的大小,若逆序則兩個元素交換位置如果一趟下來沒有發生交換,則說明序列有序,可以在序列中設置一個標志flag判斷元素是否發生交換,從而來減少不必要的比較(在寫完排序算法后再寫)小結:一共進行數組大小-1次的外…

使用openssl開源AES算法,實現aes、aes-cbc和aes-ecb對字符串的加解密

注意事項 對于用戶輸入的密碼進行了md5運算&#xff0c;從而保證數據格式的統一性 內部調用的隨機函數&#xff0c;參考我的其他博文 參考鏈接 頭文件crypto_util.h #pragma once#include <string>namespace hsm{namespace mgmt{void get_md5_digest(const std::strin…

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、獲取途…

使用memcmp函數判斷兩個函數的前n位字節數是否相等

memcmp函數的介紹 頭文件&#xff1a;#include <string.h>定義函數&#xff1a;int memcmp (const void *s1, const void *s2, size_t n);函數說明&#xff1a;memcmp()用來比較s1 和s2 所指的內存區間前n 個字符。字符串大小的比較是以ASCII 碼表上的順序來決定&#x…

java 選擇排序

選擇排序–時間復雜度n^2 第一次從arr[0]–arr[n-1]中選出最小值,與arr[0]交換 第二次從arr[1]–arr[n-1]中選出最小值,與arr[1]交換… 最小數:假定當前這個數是最小數,然后和后面的每個數進行比較,當發現有更小的數時,重定最小數與最小數的下標 總結: 選擇排序一共有數組大…

Linux環境下實現unsigned char*向string的轉換

代碼 unsigned char input_data[input_data_length] {"This is my first encrypted plaintext hello world"}; openssl_enc_string hsm::mgmt::aes_ecb_encrypt_to_string(static_cast<string>((const char * )input_data),password);使用static_cast<st…

概率論 事件關系 古典概型與幾何概型

基本知識點 隨機試驗:1.不確定性2.可預知性3.可重復性基本事件:包含一個樣本點 必然事件:全集 不可能事件:空集 子集2^n-1-1(減去空集與真集) 事件間的關系 1.包含關系 2.和運算AUBAB,A與B至少有一個發生 3.積事件A∩BAB,AB同時發生 4.差事件A-BAB ?A-AB,A發生但B不發生 5.…