自定義View-第七步:Path基礎

前言

根據Gcssloop所學習的自定義View整理與筆記。

請關閉硬件加速,以免引起不必要的問題!
在AndroidMenifest文件中application節點下添上 android:hardwareAccelerated=”false”以關閉整個應用的硬件加速。

一、Path的常用方法【look一下,后續會詳解的O(∩_∩)O~】

|作用|相關方法|備注|
|------|-----|----|
|移動起點|moveTo|移動下一次操作的起點位置|
|設置終點|setLastPoint|重置當前Path中最后一個點位置,如果在繪制之前調用,效果和moveTo相同|
|連接直線|lineTo|添加上一個點到當前點的直線到path|
|閉合路徑|close|連接第一個點到最后一個點,形成一個閉合區域|
|添加內容|addRect,addRoundRect,addOval,addCircle,addPath,addArc,arcTo|添加(矩形,圓角矩形,橢圓,圓,路徑,圓弧)到當前path|
|是否為空|isEmpty|判斷path是否為空|
|是否為矩形|isRect|判斷path是否是一個矩形|
|替換路徑|set|用新的路徑替換到當前路徑所有內容|
|偏移路徑|offset|對當前路徑之前的操作進行偏移(不會影響之后的操作)|
|貝塞爾曲線|quadTo,cubicTo|分別為二次和三次貝塞爾曲線的方法|
|rXxx方法|rMoveTo, rLineTo, rQuadTo, rCubicTo|不帶r的方法是基于原點的坐標系(偏移量),rXxx方法是基于當前點坐標系(偏移量),即以path最后的那個點|
|填充模式|setFillType, getFillType, isInverseFillType, toggleInverseFillType|設置,獲取,判斷和切換填充模式|
|提示方法|incReserve|提示path還有多少個點等待加入(可能會讓path優化存儲結構)|
|布爾操作【api19】|op|對兩個path進行布爾運算,【即取交集,并集等操作】|
|計算邊界|computeBounds|計算Path的邊界|
|重置路徑|reset,rewind|清除path中的內容【reset不保留內部數據結構,但會保留FillType,rewind會保留內部的數據結構,但不保留FillType】【FillType影響的是顯示效果,數據結構影響重建速度】
|矩陣操作|transform|矩陣變換|

二、Path詳解

看著多,其實就一點點,敲敲代碼,瞬間理解,真的

1. lineTo

paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
canvas.translate(300,300);
Path path = new Path(); 
path.lineTo(200, 200); 
path.lineTo(200,0);
canvas.drawPath(path, paint); // 繪制Path

效果圖:


lineTo效果圖

2.moveTo與setLastPoint


// moveTo,移動下一次操作的起點位置,不影響之前的操作,只影響之后的操作
public void moveTo (float x, float y)
// setLastPoint,設置之前操作的最后一個點的位置,影響之前和之后的操作
public void setLastPoint (float dx, float dy)

demo [moveTo]:

       canvas.translate(200, 200);
        Path path = new Path();
        path.lineTo(200, 200);
        path.moveTo(200,100);
        path.lineTo(200, 0);
        canvas.drawPath(path, paint);
moveTo效果圖

demo [setLastPoint]:

        canvas.translate(200, 200);
        Path path = new Path();
        path.lineTo(200, 200);
        path.setLastPoint(200,100);
        path.lineTo(200, 0);
        canvas.drawPath(path, paint);
setLastPoint效果圖

3. rLineTo與lineTo方法

       canvas.translate(100, 100);
        Path path = new Path();
//lineTo
        path.lineTo(200, 200);
        path.lineTo(200, 100);
//rLineTo
        path.rLineTo(200, 100);
      //  path.lineTo(0, 0);①
        canvas.drawPath(path, paint);

lineTo與rLineTo效果圖.png

注釋
translate將坐標移動到屏幕(100,100)的位置,也就是圖上標注坐標原點的部分,那么lineto將均以該坐標為坐標原點rlineto執行前的點為(200,100),此時,會以(200,100)為坐標原點,即下一個點的實際位置為(400,200),當然,實際坐標的位置是不會改變的,如果在①執行的話,會發現添加了從(400,200)到(0,0)[即圖上標注坐標原點] 的直線。
也就是說,lineTo和rLineTo的參考坐標不一樣。
請原諒我敘述的本領,如果不清楚的話,就自己寫個demo試試吧O(∩_∩)O~

4.close方法
用于連接當前最后一個點和最初的一個點(如果兩個點不重合的話),最終形成一個封閉的圖形,如果連接了最后一個點和第一個點仍然無法形成封閉圖形,則close什么也不做

        canvas.translate(100, 100);
        Path path = new Path();
        path.lineTo(200, 200);
        path.lineTo(200, 0);
        path.close();
        canvas.drawPath(path, paint);
close效果圖

實體三角形這樣畫

       paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.GREEN);
        Path path = new Path();
        path.moveTo(80, 200);// 此點為多邊形的起點
        path.lineTo(120, 250);
        path.lineTo(80, 250);
        path.close(); // 使這些點構成封閉的多邊形
        canvas.drawPath(path, paint);
三角形

5.addXxx與arcTo,注意區分addArc與arcTo

** 1. 基本圖形**

// 圓形
public void addCircle (float x, float y, float radius, Path.Direction dir)
// 橢圓
public void addOval (RectF oval, Path.Direction dir)
// 矩形
public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
public void addRect (RectF rect, Path.Direction dir)
// 圓角矩形
public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)
  • Path.Direction :在添加圖形時確定閉合順序,對圖形的渲染結果有影響,因此參數中點的順序很重要!。
    cw:順時針;ccw:逆時針
    cw demo:
        canvas.translate(250, 250);
        Path path = new Path();
        //得到一個矩形,順時針繪制矩形,左下角為最后一個點,獲得①
        path.addRect(-100,-100,200,200, Path.Direction.CW);
        canvas.drawPath(path,paint);
        //重置最有后一個點的位置,獲得②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一個矩形,獲得③
        path.addRect(-160,-160,260,260,Path.Direction.CW);
        canvas.drawPath(path, paint);
效果圖.png

這個時候把③注釋,

     canvas.translate(250, 250);
        Path path = new Path();
        //得到一個矩形①
        path.addRect(-100,-100,200,200, Path.Direction.CW);
       // canvas.drawPath(path,paint);
        //重置最后一個點的位置②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一個矩形③
       //  path.addRect(-160,-160,260,260,Path.Direction.CW);
      // canvas.drawPath(path, paint);

則得到如下效果:


內心崩潰.jpg

為啥缺了一角?哈哈,因為沒關閉硬件加速,記得關閉硬件加速哦,效果就是這樣子的啦:

完美.jpg

ccw demo:

        canvas.translate(250, 250);
        Path path = new Path();
        //得到一個逆時針繪制的矩形,右上角為最后的一個點①
        path.addRect(-100,-100,200,200, Path.Direction.CCW);
        //重置最后一個點的位置②
        path.setLastPoint(-150,250);
        canvas.drawPath(path, paint);
        //得到一個矩形③
        path.addRect(-160,-160,260,260,Path.Direction.CW);
        canvas.drawPath(path, paint);

為了顯示隱藏的那一角,我們還將③執行哈:


ccw效果圖

2. addPath:將兩個Path合并成為一個

public void addPath (Path src)
//將src進行了位移之后再添加進當前path中
public void addPath (Path src, float dx, float dy)
//將src使用Matrix進行變換后再添加到當前path中,同樣的,Matrix后續講解
public void addPath (Path src, Matrix matrix)

demo:

       canvas.translate(250, 250);
        Path path = new Path();
        Path src = new Path();
        path.addRect(-100,-100,200,200, Path.Direction.CCW);
        path.setLastPoint(-150,250);
        src.addRect(-160,-160,260,260,Path.Direction.CW);
     //合并路徑
        path.addPath(src);
    //繪制合并后的路徑
        canvas.drawPath(path, paint);

效果圖和ccw效果圖是一樣滴,看上面最后一張圖??~

3.addArc與arcTo:添加一個圓弧到path

// addArc
public void addArc (RectF oval, float startAngle, float sweepAngle)
// arcTo
public void arcTo (RectF oval, float startAngle, float sweepAngle)
public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
  • oval:圓弧的外切矩形
  • startAngle:開始角度
  • sweepAngle: 掃過角度(-360<=sweepAngle<360),當 >= 360 或者 < -360 時將不會繪制任何內容
  • forceMoveTo:是否強制使用MoveTo

addArc與arcTo的區別:

  1. addArc:直接添加一個圓弧到path中
  2. arcTo:添加一個圓弧到path,如果圓弧的起點和路徑上次最后一個坐標點不相同,就連接兩個點
    不過->如果有forceMoveTo,還是要看forceMoveTo的取值的哦。
forceMoveTo 含義 等價方法
true 不連接最后一個點與圓弧起點,不補全路徑 public void addArc (RectF oval, float startAngle, float sweepAngle)
false 連接最后一個點與圓弧起點,即補全路徑 public void arcTo (RectF oval, float startAngle, float sweepAngle)

看下邊demo了解一下區別??
demo addArc (arcTo true):

        canvas.translate(250, 250);
        Path path = new Path();
        path.lineTo(100, 100);
        
        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawRect(rectF, paint);
        
        path.addArc(rectF, 0, 230);
        //等價于下邊的作用
        // path.arcTo(rectF,0,230,true);
        canvas.drawPath(path, paint);
addArc效果圖

demo arcTo (arcTo false):

   canvas.translate(250, 250);
        Path path = new Path();
        path.lineTo(100, 100);

        RectF rectF = new RectF(0, 0, 200, 200);
        canvas.drawRect(rectF, paint);

        path.arcTo(rectF, 0, 230);
        //等價于下邊的作用
        //path.arcTo(rectF, 0, 230, false);
        canvas.drawPath(path, paint);
arcTo效果圖

OK啦,這就是區別了,簡單來說,就是是否自動補全路徑。

4.isEmpty、 isRect、 set 和 offset

  1. isRect:
        Path path = new Path();
        Log.d("isEmpty1","isEmpty"+path.isEmpty());
        path.lineTo(100, 100);
        Log.d("isEmpty2","isEmpty"+path.isEmpty());
  /**
  *結果如下:
  * D/isEmpty1: isEmptytrue
  * D/isEmpty2: isEmptyfalse
  1. isRect:判斷path是否是一個矩形,如果是一個矩形的話,會將矩形的信息存放進參數rect中。
       canvas.translate(50, 50);
        Path path = new Path();
        path.lineTo(0,400);
        path.lineTo(400,400);
        path.lineTo(400,0);
        path.lineTo(0,0);
        RectF rectF = new RectF();
        boolean rect = path.isRect(rectF);
        Log.d("isRect","isRect"+rect+"left:"+rectF.left);
/**
*結果是:
 *D/isRect: isRecttrueleft:0.0
**/
  1. set
       canvas.translate(160, 160);
        Path path = new Path(); 
        path.addRect(0, 0, 200, 200, Path.Direction.CW);

        Path src = new Path(); 
        src.addCircle(0, 0, 100, Path.Direction.CW);
        path.set(src); 
        canvas.drawPath(path, paint);
結果是一個圓
  1. offset:對path進行一段平移,只作用于當前的path
        public void offset (float dx, float dy)
        public void offset (float dx, float dy, Path dst)
  • Path dst:存儲平移后的path
    1. dst不為空:將當前path平移后的狀態存入dst中,不會影響當前path
    2. dst為空(null) :平移將作用于當前path,相當于第一種方法

補充

還記得上一節我們還沒講的方法么?根據路徑繪制文字

public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
public void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
  • text指文本內容
  • hOffset參數指定水平偏移
  • vOffset指定垂直偏移
        paint.setTextSize(24);
        paint.setColor(Color.BLUE);
        Path path = new Path();
        path.addArc(new RectF(0,0,100,100),10,209);
        canvas.drawTextOnPath("hello world hello world hello world ",path,0,0,paint);
效果圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容