前言
根據(jù)Gcssloop所學習的自定義View整理與筆記。
一.填充模式
填充模式相關(guān)方法
| 方法 | 作用 |
|---|---|
| setFillType | 設置填充規(guī)則 |
| getFillType | 獲取當前填充規(guī)則 |
| isInverseFillType | 判斷是否是反向(INVERSE)規(guī)則 |
| toggleInverseFillType | 切換填充規(guī)則(即原有規(guī)則與反向規(guī)則之間相互切換) |
填充規(guī)則有四種
| 模式 | 簡介 |
|---|---|
| EVEN_ODD | 奇偶規(guī)則 |
| INVERSE_EVEN_ODD | 反奇偶規(guī)則 |
| WINDING | 非零環(huán)繞數(shù)規(guī)則 |
| INVERSE_WINDING | 反非零環(huán)繞數(shù)規(guī)則 |
** 1. 我們首先了解一下什么是奇偶規(guī)則。**
奇偶規(guī)則:如果是奇數(shù),那么要被填充,如果是偶數(shù)則不填充。那么,怎么判斷奇數(shù)還是偶數(shù)呢?
從任意位置p作一條射線, 若與該射線相交的圖形邊的數(shù)目為奇數(shù),需要被填充,否則是偶數(shù),不被填充。

可以看出,
P1: 從P1發(fā)出一條射線,發(fā)現(xiàn)圖形與該射線相交邊數(shù)為0,偶數(shù),不被填充。
P2: 從P2發(fā)出一條射線,發(fā)現(xiàn)圖形與該射線相交邊數(shù)為1,奇數(shù),被填充。
P3: 從P3發(fā)出一條射線,發(fā)現(xiàn)圖形與該射線相交邊數(shù)為2,偶數(shù),不被填充。
注意:奇偶規(guī)則與方向無關(guān)。

自然,反奇偶規(guī)則剛好與奇偶規(guī)則是相反的,不在贅述咯!
** 2. 非零環(huán)繞數(shù)規(guī)則揭秘**
假如一個點被從左到右跨過,計數(shù)器+1,從右到左跨過,計數(shù)器-1,最后,如果結(jié)果是0,那么不填充,如果是非零,那么填充。
注意:非零環(huán)繞數(shù)規(guī)則與方向有關(guān)哦,Path中任何線段都是有方向性的,這也是使用非零環(huán)繞數(shù)規(guī)則的基礎(chǔ)。

P1: 從P1點發(fā)出一條射線,沿射線防線移動,并沒有與邊相交點部分,環(huán)繞數(shù)為0,故不填充。
P2: 從P2點發(fā)出一條射線,沿射線方向移動,與圖形點左側(cè)邊相交,該邊從左到右穿過穿過射線,環(huán)繞數(shù)-1,最終環(huán)繞數(shù)為-1,故填充。
P3: 從P3點發(fā)出一條射線,沿射線方向移動,在第一個交點處,底邊從右到左穿過射線,環(huán)繞數(shù)+1,在第二個交點處,右側(cè)邊從左到右穿過射線,環(huán)繞數(shù)-1,最終環(huán)繞數(shù)為0,故不填充。

自然,反非零環(huán)繞數(shù)規(guī)則是與非零環(huán)繞數(shù)規(guī)則是相反的,也不在贅述咯!
接下來,就以非零環(huán)繞規(guī)則舉個demo吧
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
canvas.translate(300, 300);
Path path = new Path();
//內(nèi)外同向
path.addRect(-200, -200, 200, 200, Path.Direction.CCW);
// path.addRect(-100, -100, 100, 100, Path.Direction.CCW);
//內(nèi)外不同向
path.addRect(-100, -100, 100, 100, Path.Direction.CW);
//非零環(huán)繞數(shù)規(guī)則
path.setFillType(Path.FillType.WINDING);
canvas.drawPath(path, paint);
效果圖


二.布爾操作(API19)
1.Path的布爾運算邏輯
| 名稱 | 類比 | 說明 | 示意圖 |
|---|---|---|---|
| DIFFREENCE | 差集 | Path1中減去Path2后剩下的部分 | ![]() |
| REVERSE_DIFFERENCE | 差集 | Path2中減去Path1后剩下的部分 | ![]() |
| INTERSECT | 交集 | Path1與Path2相交的部分 | ![]() |
| UNION | 并集 | 包含全部Path1和Path2 | ![]() |
| XOR | 異或 | 包含Path1和Path2但不包含兩者相交的部分 | ![]() |
2.布爾運算的方法
boolean op (Path path, Path.Op op)
boolean op (Path path1, Path path2, Path.Op op)
詳細說明的話,咱們得舉個小小例子
// 對 path1 和 path2 執(zhí)行布爾運算,運算方式由第二個參數(shù)指定,運算結(jié)果存入到path1中。
path1.op(path2, Path.Op.DIFFERENCE);
// 對 path1 和 path2 執(zhí)行布爾運算,運算方式由第三個參數(shù)指定,運算結(jié)果存入到path3中。
path3.op(path1, path2, Path.Op.DIFFERENCE)
來個太極demo:
canvas.drawColor(Color.YELLOW);
paint.setStyle(Paint.Style.FILL);
canvas.translate(300, 300);
//繪制一個白色的圓
paint.setColor(Color.WHITE);
canvas.drawCircle(0,0,200,paint);
//繪制太極
paint.setColor(Color.BLACK);
Path path1 = new Path();
Path path2 = new Path();
Path path3 = new Path();
Path path4 = new Path();
path1.addCircle(0, 0, 200, Path.Direction.CW);
path2.addRect(0, -200, 200, 200, Path.Direction.CW);
path3.addCircle(0, -100, 100, Path.Direction.CW);
path4.addCircle(0, 100, 100, Path.Direction.CW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//path1減去path2,將結(jié)果存入path1
path1.op(path2, Path.Op.DIFFERENCE);
//包含全部path1和path3,將結(jié)果存入path1
path1.op(path3, Path.Op.UNION);
//path1減去path4,將結(jié)果存入path1
path1.op(path4, Path.Op.DIFFERENCE);
}
//繪制path1
canvas.drawPath(path1, paint);

小記:API<19的,要使用Region的op,Region我們將會放在自定義View-第十二步:Region講解。
三.計算邊界
void computeBounds (RectF bounds, boolean exact)
- bounds:測試結(jié)果會放入這個矩形
- exact :是否精確測量,這個參數(shù)作用目前已被廢棄,寫true即可
//----------
//上個demo的代碼
//在下邊加上如下代碼,測量path1的邊界
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
RectF rect = new RectF();
path1.computeBounds(rect, true);
canvas.drawRect(rect, paint);

四.重置路徑reset和rewind
|方法| 是否保留FillType設置| 是否保留原有數(shù)據(jù)結(jié)構(gòu)|
|--------|--------|------|
|reset| 是 |否|
|rewind |否| 是|
這個兩個方法應該何時選擇呢?
選擇權(quán)重: FillType > 數(shù)據(jù)結(jié)構(gòu)
因為“FillType”影響的是顯示效果,而“數(shù)據(jù)結(jié)構(gòu)”影響的是重建速度。




