編輯:關於Android編程
為了兼容性(偷懶) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,為啥看起來有些順手就能寫的重載方法要等到API21才添加上啊。寶寶此刻內心也是崩潰的。
此類方法可以看到和前面的一些方法看起來很像,只是在前面多了一個r,那麼這個rXxx和前面的一些方法有什麼區別呢?
rXxx方法的坐標使用的是相對位置(基於當前點的位移),而之前方法的坐標是絕對位置(基於當前坐標系的坐標)。
舉個例子:
Path path = new Path();
path.moveTo(100,100);
path.lineTo(100,200);
canvas.drawPath(path,mDeafultPaint);
在這個例子中,先移動點到坐標(100,100)處,之後再連接 點(100,100) 到 (100,200) 之間點直線,非常簡單,畫出來就是一條豎直的線,那接下來看下一個例子:
Path path = new Path();
path.moveTo(100,100);
path.rLineTo(100,200);
canvas.drawPath(path,mDeafultPaint);
這個例子中,將 lineTo 換成了 rLineTo 可以看到在屏幕上原本是豎直的線變成了傾斜的線。這是因為最終我們連接的是 (100,100) 和 (200, 300) 之間的線段。
在使用rLineTo之前,當前點的位置在 (100,100) , 使用了 rLineTo(100,200) 之後,下一個點的位置是在當前點的基礎上加上偏移量得到的,即 (100+100, 100+200) 這個位置,故最終結果如上所示。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxzdHJvbmc+UFM6ILTLtKa99tLUIHJMaW5lVG8gzqrA/aOs1rvSqsDtveIgJmxkcXVvO774ttTX+LHqJnJkcXVvOyC6zSAmbGRxdW87z+C21Nf4seomcmRxdW87ILXEx/ix8KOsxuTL+7e9t6jA4LHIvLS/yaGjPC9zdHJvbmc+PC9wPg0KPGgzIGlkPQ=="填充模式">填充模式
我們在之前的文章中了解到,Paint有三種樣式,“描邊” “填充” 以及 “描邊加填充”,我們這裡所了解到就是在Paint設置為後兩種樣式時不同的填充模式對圖形渲染效果的影響。
我們要給一個圖形內部填充顏色,首先需要分清哪一部分是外部,哪一部分是內部,機器不像我們人那麼聰明,機器是如何判斷內外呢?
機器判斷圖形內外,一般有以下兩種方法:
PS:此處所有的圖形均為封閉圖形,不包括圖形不封閉這種情況。
接下來我們先了解一下兩種判斷方法是如何工作的。
這一個比較簡單,也容易理解,直接用一個簡單示例來說明。
在上圖中有一個四邊形,我們選取了三個點來判斷這些點是否在圖形內部。
>
P1: 從P1發出一條射線,發現圖形與該射線相交邊數為0,偶數,故P1點在圖形外部。
P2: 從P2發出一條射線,發現圖形與該射線相交邊數為1,奇數,故P2點在圖形內部。
P3: 從P3發出一條射線,發現圖形與該射線相交邊數為2,偶數,故P3點在圖形外部。
非零環繞數規則相對來說比較難以理解一點。
我們在之前的文章 AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md">Path之基本操作 中我們了解到,在給Path中添加圖形時需要指定圖形的添加方式,是用順時針還是逆時針,另外我們不論是使用lineTo,quadTo,cubicTo還是其他連接線的方法,都是從一個點連接到另一個點,換言之,Path中任何線段都是有方向性的,這也是使用非零環繞數規則的基礎。
我們依舊用一個簡單的例子來說明非零環繞數規則的用法:
PS: 注意圖形中線段的方向性!
>
P1: 從P1點發出一條射線,沿射線防線移動,並沒有與邊相交點部分,環繞數為0,故P1在圖形外邊。
P2: 從P2點發出一條射線,沿射線方向移動,與圖形點左側邊相交,該邊從左到右穿過穿過射線,環繞數-1,最終環繞數為-1,故P2在圖形內部。
P3: 從P3點發出一條射線,沿射線方向移動,在第一個交點處,底邊從右到左穿過射線,環繞數+1,在第二個交點處,右側邊從左到右穿過射線,環繞數-1,最終環繞數為0,故P3在圖形外部。
通常,這兩種方法的判斷結果是相同的,但也存在兩種方法判斷結果不同的情況,如下面這種情況:
注意圖形線段的方向,就不詳細解釋了,用上面的方法進行判斷即可。
自相交圖形定義:多邊形在平面內除頂點外還有其他公共點。
簡單的提一下自相交圖形,了解概念即可,下圖就是一個簡單的自相交圖形:
Android中的填充模式有四種,是封裝在Path中的一個枚舉。
我們可以看到上面有四種模式,分成兩對,例如 “奇偶規則” 與 “反奇偶規則” 是一對,它們之間有什麼關系呢?
Inverse 和含義是“相反,對立”,說明反奇偶規則剛好與奇偶規則相反,例如對於一個矩形而言,使用奇偶規則會填充矩形內部,而使用反奇偶規則會填充矩形外部,這個會在後面示例中代碼展示兩者對區別。
這些都是Path中的方法。
本演示著重於幫助理解填充模式中的一些難點和易混淆的問題,對於一些比較簡單的問題,讀者可自行驗證,本文中不會過多贅述。
mDeafultPaint.setStyle(Paint.Style.FILL); // 設置畫布模式為填充
canvas.translate(mViewWidth / 2, mViewHeight / 2); // 移動畫布(坐標系)
Path path = new Path(); // 創建Path
//path.setFillType(Path.FillType.EVEN_ODD); // 設置Path填充模式為 奇偶規則
path.setFillType(Path.FillType.INVERSE_WINDING); // 反奇偶規則
path.addRect(-200,-200,200,200, Path.Direction.CW); // 給Path中添加一個矩形
下面兩張圖片分別是在奇偶規則於反奇偶規則的情況下繪制的結果,可以看出其填充的區域剛好相反:
PS: 白色為背景色,黑色為填充色。
我們之前討論過給Path添加圖形時順時針與逆時針的作用,除了上次講述的方便記錄外,就是本文所涉及的另外一個重要作用了: “作為非零環繞數規則的判斷依據。”
通過前面我們已經大致了解了在圖形邊的方向會如何影響到填充效果,我們這裡驗證一下:
mDeafultPaint.setStyle(Paint.Style.FILL); // 設置畫筆模式為填充
canvas.translate(mViewWidth / 2, mViewHeight / 2); // 移動畫布(坐系)
Path path = new Path(); // 創建Path
// 添加小正方形 (通過這兩行代碼來控制小正方形邊的方向,從而演示不同的效果)
// path.addRect(-200, -200, 200, 200, Path.Direction.CW);
path.addRect(-200, -200, 200, 200, Path.Direction.CCW);
// 添加大正方形
path.addRect(-400, -400, 400, 400, Path.Direction.CCW);
path.setFillType(Path.FillType.WINDING); // 設置Path填充模式為非零環繞規則
canvas.drawPath(path, mDeafultPaint); // 繪制Path
布爾操作與我們中學所學的集合操作非常像,只要知道集合操作中等交集,並集,差集等操作,那麼理解布爾操作也是很容易的。
布爾操作是兩個Path之間的運算,主要作用是用一些簡單的圖形通過一些規則合成一些相對比較復雜,或難以直接得到的圖形。
如太極中的陰陽魚,如果用貝塞爾曲線制作的話,可能需要六段貝塞爾曲線才行,而在這裡我們可以用四個Path通過布爾運算得到,而且會相對來說更容易理解一點。
canvas.translate(mViewWidth / 2, mViewHeight / 2);
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.CCW);
path1.op(path2, Path.Op.DIFFERENCE);
path1.op(path3, Path.Op.UNION);
path1.op(path4, Path.Op.DIFFERENCE);
canvas.drawPath(path1, mDeafultPaint);
前面演示了布爾運算的作用,接下來我們了解一下布爾運算的核心:布爾邏輯。
Path的布爾運算有五種邏輯,如下:
通過前面到理論知識鋪墊,相信大家對布爾運算已經有了基本的認識和理解,下面我們用代碼演示一下布爾運算:
在Path中的布爾運算有兩個方法
boolean op (Path path, Path.Op op)
boolean op (Path path1, Path path2, Path.Op op)
兩個方法中的返回值用於判斷布爾運算是否成功,它們使用方法如下:
``
java
// 對 path1 和 path2 執行布爾運算,運算方式由第二個參數指定,運算結果存入到path1中。
path1.op(path2, Path.Op.DIFFERENCE);
// 對 path1 和 path2 執行布爾運算,運算方式由第三個參數指定,運算結果存入到path3中。
path3.op(path1, path2, Path.Op.DIFFERENCE)
#### 布爾運算示例
![](http://ww1.sinaimg.cn/large/005Xtdi2gw1f43jz8xnbxj308c0etwes.jpg)
代碼:
``` java
int x = 80;
int r = 100;
canvas.translate(250,0);
Path path1 = new Path();
Path path2 = new Path();
Path pathOpResult = new Path();
path1.addCircle(-x, 0, r, Path.Direction.CW);
path2.addCircle(x, 0, r, Path.Direction.CW);
pathOpResult.op(path1,path2, Path.Op.DIFFERENCE);
canvas.translate(0, 200);
canvas.drawText("DIFFERENCE", 240,0,mDeafultPaint);
canvas.drawPath(pathOpResult,mDeafultPaint);
pathOpResult.op(path1,path2, Path.Op.REVERSE_DIFFERENCE);
canvas.translate(0, 300);
canvas.drawText("REVERSE_DIFFERENCE", 240,0,mDeafultPaint);
canvas.drawPath(pathOpResult,mDeafultPaint);
pathOpResult.op(path1,path2, Path.Op.INTERSECT);
canvas.translate(0, 300);
canvas.drawText("INTERSECT", 240,0,mDeafultPaint);
canvas.drawPath(pathOpResult,mDeafultPaint);
pathOpResult.op(path1,path2, Path.Op.UNION);
canvas.translate(0, 300);
canvas.drawText("UNION", 240,0,mDeafultPaint);
canvas.drawPath(pathOpResult,mDeafultPaint);
pathOpResult.op(path1,path2, Path.Op.XOR);
canvas.translate(0, 300);
canvas.drawText("XOR", 240,0,mDeafultPaint);
canvas.drawPath(pathOpResult,mDeafultPaint);
這個方法主要作用是計算Path所占用的空間以及所在位置,方法如下:
void computeBounds (RectF bounds, boolean exact)
它有兩個參數:
關於exact如有疑問可參見Google官方的提交記錄Path.computeBounds()
計算path邊界的一個簡單示例.
代碼:
// 移動canvas,mViewWidth與mViewHeight在 onSizeChanged 方法中獲得
canvas.translate(mViewWidth/2,mViewHeight/2);
RectF rect1 = new RectF(); // 存放測量結果的矩形
Path path = new Path(); // 創建Path並添加一些內容
path.lineTo(100,-50);
path.lineTo(100,50);
path.close();
path.addCircle(-100,0,100, Path.Direction.CW);
path.computeBounds(rect1,true); // 測量Path
canvas.drawPath(path,mDeafultPaint); // 繪制Path
mDeafultPaint.setStyle(Paint.Style.STROKE);
mDeafultPaint.setColor(Color.RED);
canvas.drawRect(rect1,mDeafultPaint); // 繪制邊界
重置Path有兩個方法,分別是reset和rewind,兩者區別主要有一下兩點:
這個兩個方法應該何時選擇呢?
選擇權重: FillType > 數據結構
因為“FillType”影響的是顯示效果,而“數據結構”影響的是重建速度。
Path中常用的方法到此已經結束,希望能夠幫助大家加深對Path對理解運用,讓大家能夠用Path愉快的玩耍。( ̄▽ ̄)
本示例以Servlet為例,演示Android與Servlet的通信。眾所周知,Android與服務器通信通常采用HTTP通信方式和Socket通信方式,而HTTP通信方
前言當前的網絡開源庫有許多,如volley,okhttp,retrofit等,這三個庫當前是比較火的,其中,okhttp和retrofit由square團隊開發。關於這
1.SharedPrefereces 輕量級.XML 存儲文件名,數據保存在data/data/basepackage/shared_prefs/myopt.xml中 實
我們在安裝某個APP的時候,基本都會有一個引導頁的提示,他們可以打廣告,或者介紹新功能的加入和使用說明等。一般都支持滑動並且下面有幾個點,顯示共有多少頁和當前圖片的位置,