Carson帶你學(xué)Android:自定義View Path類全面解析


前言

  • 自定義View是Android開發(fā)者必須了解的基礎(chǔ);而Path類的使用在自定義View繪制中發(fā)揮著非常重要的作用
  • 網(wǎng)上有大量關(guān)于自定義View中Path類的文章,但存在一些問題:內(nèi)容不全、思路不清晰、簡(jiǎn)單問題復(fù)雜化等等
  • 今天,我將全面總結(jié)自定義View中Path類的使用,我能保證這是市面上的最全面、最清晰、最易懂的

Carson帶你學(xué)Android自定義View文章系列:
Carson帶你學(xué)Android:自定義View基礎(chǔ)
Carson帶你學(xué)Android:一文梳理自定義View工作流程
Carson帶你學(xué)Android:自定義View繪制準(zhǔn)備-DecorView創(chuàng)建
Carson帶你學(xué)Android:自定義View Measure過程
Carson帶你學(xué)Android:自定義View Layout過程
Carson帶你學(xué)Android:自定義View Draw過程
Carson帶你學(xué)Android:手把手教你寫一個(gè)完整的自定義View
Carson帶你學(xué)Android:Canvas類全面解析
Carson帶你學(xué)Android:Path類全面解析


目錄

目錄

1. 簡(jiǎn)介

  • 定義:路徑,即無(wú)數(shù)個(gè)點(diǎn)連起來的線
  • 作用:設(shè)置繪制的順序 & 區(qū)域

Path只用于描述順序 & 區(qū)域,單使用Path無(wú)法產(chǎn)生效果

  • 應(yīng)用場(chǎng)景:繪制復(fù)雜圖形(如心形、五角星等等)

Path類封裝了由直線和曲線(2、3次貝塞爾曲線)構(gòu)成的幾何路徑。


2. 基礎(chǔ)

2.1 開放路徑與閉合路徑的區(qū)別

開放路徑 & 閉合路徑

2.2 如何判斷點(diǎn)在圖形內(nèi)還是圖形外

  • 判斷方法分為奇偶規(guī)則 & 非零環(huán)繞規(guī)則,具體介紹如下:
示意圖
  • 舉例說明1:(奇偶規(guī)則)
    示意圖

由上圖知:

  • p1發(fā)出的射線與圖形相交1個(gè)點(diǎn),即奇數(shù)點(diǎn),所以P1點(diǎn)在圖形內(nèi)
  • p2發(fā)出的射線與圖形相交2個(gè)點(diǎn),即偶數(shù)點(diǎn),所以P2點(diǎn)在圖形內(nèi)
  • 舉例說明2:(非零環(huán)繞數(shù)規(guī)則)
    從上面方法分析到,任何圖形都是由點(diǎn)連成線組成的,是具備方向的,看下圖:(矩形是順時(shí)針)
    示意圖
  • p1發(fā)出的射線與圖形相交1個(gè)點(diǎn),矩形的右側(cè)線從左邊射到右邊,環(huán)繞數(shù)-1,最終環(huán)繞數(shù)為-1,故p1在圖形內(nèi)部。
  • p2發(fā)出的射線與圖形相交2個(gè)點(diǎn):矩形的右側(cè)邊從左邊射到右邊
    環(huán)繞數(shù)-1;矩形的下側(cè)邊從右邊射到左邊,環(huán)繞數(shù)+1,最終環(huán)繞數(shù)為0.故p2在圖形外部

3. 具體使用

3.1 對(duì)象創(chuàng)建

// 使用Path首先要new一個(gè)Path對(duì)象
// Path的起點(diǎn)默認(rèn)為坐標(biāo)為(0,0)
Path path = new Path();
// 特別注意:建全局Path對(duì)象,在onDraw()按需修改;盡量不要在onDraw()方法里new對(duì)象
// 原因:若View頻繁刷新,就會(huì)頻繁創(chuàng)建對(duì)象,拖慢刷新速度。

3.2 具體方法使用

因?yàn)閜ath類的方法都是聯(lián)合使用,所以下面將一組組方法進(jìn)行介紹。

第一組:設(shè)置路徑

采用moveTo()、setLastPoint()、lineTo()、close()組合

// 設(shè)置當(dāng)前點(diǎn)位置
// 后面的路徑會(huì)從該點(diǎn)開始畫
moveTo(float x, float y) ;

// 當(dāng)前點(diǎn)(上次操作結(jié)束的點(diǎn))會(huì)連接該點(diǎn)
// 如果沒有進(jìn)行過操作則默認(rèn)點(diǎn)為坐標(biāo)原點(diǎn)。
lineTo(float x, float y)  ;

// 閉合路徑,即將當(dāng)前點(diǎn)和起點(diǎn)連在一起
// 注:如果連接了最后一個(gè)點(diǎn)和第一個(gè)點(diǎn)仍然無(wú)法形成封閉圖形,則close什么也不做
close() ;
  • 可使用setLastPoint()設(shè)置當(dāng)前點(diǎn)位置(代替moveTo()
  • 二者區(qū)別:


    Paste_Image.png

實(shí)例介紹:(含setLastPoint()moveTo()


 // 使用moveTo()
 // 起點(diǎn)默認(rèn)是(0,0)
        //連接點(diǎn)(400,500)
        path.lineTo(400, 500);

        // 將當(dāng)前點(diǎn)移動(dòng)到(300, 300)
        path.moveTo(300, 300) ;

        //連接點(diǎn)(900, 800)
        path.lineTo(900, 800);

        // 閉合路徑,即連接當(dāng)前點(diǎn)和起點(diǎn)
        // 即連接(200,700)與起點(diǎn)2(300, 300)
        // 注:此時(shí)起點(diǎn)已經(jīng)進(jìn)行變換
        path.close();

        // 畫出路徑
        canvas.drawPath(path, mPaint1);

// 使用setLastPoint()
// 起點(diǎn)默認(rèn)是(0,0)
        //連接點(diǎn)(400,500)
        path.lineTo(400, 500);

        // 將當(dāng)前點(diǎn)移動(dòng)到(300, 300)
        // 會(huì)影響之前的操作
        // 但不將此設(shè)置為新起點(diǎn)
        path.setLastPoint(300, 300) ;

        //連接點(diǎn)(900,800)
        path.lineTo(900, 800);

        //連接點(diǎn)(200,700)
        path.lineTo(200, 700);

        // 閉合路徑,即連接當(dāng)前點(diǎn)和起點(diǎn)
        // 即連接(200,700)與起點(diǎn)(0,0)
        // 注:起點(diǎn)一直沒變化
        path.close();

        // 畫出路徑
        canvas.drawPath(path, mPaint1);
效果圖

關(guān)于重置路徑

  • 重置Path有兩個(gè)方法:reset()rewind()
  • 兩者區(qū)別在于:
方法 是否保留FillType設(shè)置 是否保留原有數(shù)據(jù)結(jié)構(gòu)
Path.reset()
Path.rewind()
  1. FillType影響顯示效果;數(shù)據(jù)結(jié)構(gòu)影響重建速度
  2. 所以一般選擇Path.reset()

由于較簡(jiǎn)單,此處不作過多展示。

第二組: 添加路徑

采用addXxx()、arcTo()組合

2.1 添加基本圖形

  • 作用:在Path路徑中添加基本圖形

如圓形路徑、圓弧路徑等等

  • 具體使用
 
// 添加圓弧
// 方法1
public void addArc (RectF oval, float startAngle, float sweepAngle)

//  startAngle:確定角度的起始位置
//  sweepAngle : 確定掃過的角度
 
    // 方法2
    // 與上面方法唯一不同的是:如果圓弧的起點(diǎn)和上次最后一個(gè)坐標(biāo)點(diǎn)不相同,就連接兩個(gè)點(diǎn)
    public void arcTo (RectF oval, float startAngle, float sweepAngle)
   
   // 方法3
   // 參數(shù)forceMoveTo:是否將之前路徑的結(jié)束點(diǎn)設(shè)置為圓弧起點(diǎn)
   // true:在新的起點(diǎn)畫圓弧,不連接最后一個(gè)點(diǎn)與圓弧起點(diǎn),即與之前路徑?jīng)]有交集(同addArc())
  // false:在新的起點(diǎn)畫圓弧,但會(huì)連接之前路徑的結(jié)束點(diǎn)與圓弧起點(diǎn),即與之前路徑有交集(同arcTo(3參數(shù)))
    public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
// 下面會(huì)詳細(xì)說明


  // 加入圓形路徑
  // 起點(diǎn):x軸正方向的0度
  // 其中參數(shù)dir:指定繪制時(shí)是順時(shí)針還是逆時(shí)針:CW為順時(shí)針,  CCW為逆時(shí)針
  // 路徑起點(diǎn)變?yōu)閳A在X軸正方向最大的點(diǎn)
  addCircle(float x, float y, float radius, Path.Direction dir)   

   // 加入橢圓形路徑
  // 其中,參數(shù)oval作為橢圓的外切矩形區(qū)域
  addOval(RectF oval, Path.Direction dir)    

  // 加入矩形路徑
  // 路徑起點(diǎn)變?yōu)榫匦蔚淖笊辖琼旤c(diǎn)
  addRect(RectF rect, Path.Direction dir)     

  //加入圓角矩形路徑
  
  addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)      
 
//  注:添加圖形路徑后會(huì)改變路徑的起點(diǎn)

主要說一下dir這個(gè)參數(shù):

dir = Direction = 圖形的方向,為枚舉類型:

  • CW:clockwise,順時(shí)針
  • CCW:counter-clockwise,逆時(shí)針

圖形的方向影響的是:

  • 添加圖形時(shí)確定閉合順序(各個(gè)點(diǎn)的記錄順序)
  • 圖形的渲染結(jié)果(是判斷圖形渲染的重要條件)

圖形繪制的本質(zhì):先畫點(diǎn),再將點(diǎn)連接起來。所以,點(diǎn)與點(diǎn)之間是存在一個(gè)先后順序的;順時(shí)針和逆時(shí)針用于確定這些點(diǎn)的順序。

下面實(shí)例將說明:

  // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(350, 500);
        // 順時(shí)針
        path.addRect(0, 0, 400, 400, Path.Direction.CW);
        
        // 逆時(shí)針
//        path.addRect(0,0,400,400, Path.Direction.CCW);
        canvas.drawPath(path,mPaint1);
效果圖

關(guān)于加入圖形路徑后會(huì)影響路徑的起點(diǎn),實(shí)例如下:

  // 軌跡1
        // 將Canvas坐標(biāo)系移到屏幕正中
           canvas.translate(400,500);
        
        // 起點(diǎn)是(0,0),連接點(diǎn)(-100,0)
            path.lineTo(-100,0);
        // 連接點(diǎn)(-100,200)
            path.lineTo(-100,200);
        // 連接點(diǎn)(200,200)
            path.lineTo(200,200);
        // 閉合路徑,即連接當(dāng)前點(diǎn)和起點(diǎn)
        // 即連接(200,200)與起點(diǎn)是(0,0)
            path.close();

        // 畫出路徑
            canvas.drawPath(path,paint);
        // 具體請(qǐng)看下圖


// 軌跡2
        // 將Canvas坐標(biāo)系移到屏幕正中
            canvas.translate(400,500);
        
        // 起點(diǎn)是(0,0),連接點(diǎn)(-100,0)
            path.lineTo(-100,0);
        // 畫圓:圓心=(0,0),半徑=100px
        // 此時(shí)路徑起點(diǎn)改變 = (0,100)(記為起點(diǎn)2)
        // 起點(diǎn)改變?cè)瓌t:新畫圖形在x軸正方向的最后一個(gè)坐標(biāo)
        // 后面路徑的變化以這個(gè)點(diǎn)繼續(xù)下去
            path.addCircle(0,0,100, Path.Direction.CCW);

        // 起點(diǎn)為:(0,100),連接 (-100,200)
            path.lineTo(-100,200);
        // 連接 (200,200)
            path.lineTo(200,200);

        // 閉合路徑,即連接當(dāng)前點(diǎn)和起點(diǎn)(注:閉合的是起點(diǎn)2)
        // 即連接(200,200)與起點(diǎn)2(0,100)
            path.close();
        
        // 畫出路徑
            canvas.drawPath(path,paint);

        // // 具體請(qǐng)看下圖

效果圖

這里著重說明:添加圓弧路徑(addArc與arcTo)

 // addArc
// 直接添加一個(gè)圓弧到path中
//  startAngle:確定角度的起始位置
//  sweepAngle : 確定掃過的角度
    public void addArc (RectF oval, float startAngle, float sweepAngle)


    // arcTo
    // 方法1
    // 同樣是添加一個(gè)圓弧到path
    // 與上面方法唯一不同的是:如果圓弧的起點(diǎn)和上次最后一個(gè)坐標(biāo)點(diǎn)不相同,就連接兩個(gè)點(diǎn)
    public void arcTo (RectF oval, float startAngle, float sweepAngle)
   
   // 方法2
   // 參數(shù)forceMoveTo:是否將之前路徑的結(jié)束點(diǎn)設(shè)置為圓弧起點(diǎn)
   // true:在新的起點(diǎn)畫圓弧,不連接最后一個(gè)點(diǎn)與圓弧起點(diǎn),即與之前路徑?jīng)]有交集(同addArc())
  // false:在新的起點(diǎn)畫圓弧,但會(huì)連接之前路徑的結(jié)束點(diǎn)與圓弧起點(diǎn),即與之前路徑有交集(同arcTo(3參數(shù)))
    public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

具體請(qǐng)看下面實(shí)例


// 將一個(gè)圓弧路徑添加到一條直線路徑里

 // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(350, 500);

        // 先將原點(diǎn)(0,0)連接點(diǎn)(100,100)
        path.lineTo(50, 200);

// 添加圓弧路徑(2分之1圓弧)

        // 不連接最后一個(gè)點(diǎn)與圓弧起點(diǎn)
        path.addArc(new RectF(200, 200, 300, 300), 0, 180);
        // path.arcTo(oval,0,270,true);             // 與上面一句作用等價(jià)
        
        // 連接之前路徑的結(jié)束點(diǎn)與圓弧起點(diǎn)
        path.arcTo(new RectF(200, 200, 300, 300), 0, 180);
        // path.arcTo(oval,0,270,false);             // 與上面一句作用等價(jià)
        
        // 畫出路徑
        canvas.drawPath(path, mPaint1);

效果圖

2.2 添加路徑

  • 作用:合并路徑

即將路徑1加到路徑2里

  • 具體使用
    // 方法1
    public void addPath (Path src)

    // 方法2
    // 先將src進(jìn)行(x,y)位移之后再添加到當(dāng)前path
    public void addPath (Path src, float dx, float dy)

    // 方法3
    // 先將src進(jìn)行Matrix變換再添加到當(dāng)前path
    public void addPath (Path src, Matrix matrix)


// 實(shí)例:合并矩形路徑和圓形路徑

     // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(350, 500);
     // 創(chuàng)建路徑的對(duì)象
        Path pathRect = new Path();
        Path  pathCircle = new Path();
        // 畫一個(gè)矩形路徑
        pathRect.addRect(-200, -200, 200, 200, Path.Direction.CW);
        // 畫一個(gè)圓形路徑
        pathCircle.addCircle(0, 0, 100, Path.Direction.CW);

        // 將圓形路徑移動(dòng)(0,200),再添加到矩形路徑里
        pathRect.addPath(pathCircle, 0, 200);

        // 繪制合并后的路徑
        canvas.drawPath(pathRect,mPaint1);
效果圖

第三組:判斷路徑屬性

  • 采用isEmpty()、 isRect()、isConvex()、 set() 和 offset()組合

  • 具體使用:

// 判斷path中是否包含內(nèi)容
 public boolean isEmpty ()
// 例子:
Path path = new Path();
path.isEmpty();  //返回false

 path.lineTo(100,100); // 返回true


// 判斷path是否是一個(gè)矩形
// 如果是一個(gè)矩形的話,會(huì)將矩形的信息存放進(jìn)參數(shù)rect中。
public boolean isRect (RectF rect)

// 實(shí)例
path.lineTo(0,400);
        path.lineTo(400,400);
        path.lineTo(400,0);
        path.lineTo(0,0);

        RectF rect = new RectF();
        boolean b = path.isRect(rect);  // b返回ture,
        // rect存放矩形參數(shù),具體如下:
        // rect.left = 0
        // rect.top = 0
        // rect.right = 400
        // rect.bottom = 400



// 將新的路徑替代現(xiàn)有路徑
 public void set (Path src)

        // 實(shí)例
        // 設(shè)置一矩形路徑
        Path path = new Path();                     
        path.addRect(-200,-200,200,200, Path.Direction.CW);
      
        // 設(shè)置一圓形路徑
        Path src = new Path();                     
        src.addCircle(0,0,100, Path.Direction.CW);

        // 將圓形路徑代替矩形路徑
        path.set(src);      

        // 繪制圖形
        canvas.drawPath(path,mPaint);


// 平移路徑
// 與Canvas.translate ()平移畫布類似
                     

// 方法1
// 參數(shù)x,y:平移位置
public void offset (float dx, float dy)

// 方法2
// 參數(shù)dst:存儲(chǔ)平移后的路徑狀態(tài),但不影響當(dāng)前path
// 可通過dst參數(shù)繪制存儲(chǔ)的路徑
        public void offset (float dx, float dy, Path dst)



 // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(350, 500);

        // path中添加一個(gè)圓形(圓心在坐標(biāo)原點(diǎn))
        path = new Path();
        path.addCircle(0, 0, 100, Path.Direction.CW);

        // 平移路徑并存儲(chǔ)平移后的狀態(tài)
        Path dst = new Path();
        path.offset(400, 0, dst);                     // 平移

        canvas.drawPath(path, mPaint1);               // 繪制path

        
        // 通過dst繪制平移后的圖形(紅色)
        mPaint1.setColor(Color.RED);      
        canvas.drawPath(dst,mPaint1);

效果圖

第四組:設(shè)置路徑填充顏色

  • 在Android中,有四種填充模式,具體如下

均封裝在Path類中

填充模式 介紹
EVEN_ODD 奇偶規(guī)則
INVERSE_EVEN_ODD 反奇偶規(guī)則
WINDING 非零環(huán)繞數(shù)規(guī)則
INVERSE_WINDING 反非零環(huán)繞數(shù)規(guī)則

請(qǐng)記住兩個(gè)填充規(guī)律:

從我之前的文章(1)自定義View基礎(chǔ) - 最易懂的自定義View原理系列提到,圖形是存在方向的(畫圖 = 連接點(diǎn)成的線 = 有連接順序)。

填充規(guī)則
  • 具體使用
// 設(shè)置填充規(guī)則
path.setFillType()
// 可填規(guī)則
// 1. EVEN_ODD:奇偶規(guī)則
// 2. INVERSE_EVEN_ODD:反奇偶規(guī)則
// 3. WINDING :非零環(huán)繞數(shù)規(guī)則
// 4. INVERSE_WINDING:反非零環(huán)繞數(shù)規(guī)則

// 理解奇偶規(guī)則和反奇偶規(guī)則:填充效果相反
// 舉例:對(duì)于一個(gè)矩形而言,使用奇偶規(guī)則會(huì)填充矩形內(nèi)部,而使用反奇偶規(guī)則會(huì)填充矩形外部(下面會(huì)舉例說明)

// 獲取當(dāng)前填充規(guī)則
path.getFillType()

// 判斷是否是反向(INVERSE)規(guī)則
path.isInverseFillType()

// 切換填充規(guī)則(即原有規(guī)則與反向規(guī)則之間相互切換)
path.toggleInverseFillType()

實(shí)例1:(奇偶規(guī)則)


 // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(350, 500);

        // 在Path中添加一個(gè)矩形
        path.addRect(-200, -200, 200, 200, Path.Direction.CW);

        // 設(shè)置Path填充模式為 奇偶規(guī)則
        path.setFillType(Path.FillType.EVEN_ODD);

        // 反奇偶規(guī)則
        // path.setFillType(Path.FillType.INVERSE_EVEN_ODD);

        // 畫出路徑
        canvas.drawPath(path, mPaint1);

舉例2:(非零環(huán)繞規(guī)則)

    // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(550, 550);
        // 在路徑中添加大正方形
        // 逆時(shí)針
        path.addRect(-400, -400, 400, 400, Path.Direction.CCW);

        // 在路徑中添加小正方形
        // 順時(shí)針
//        path.addRect(-200, -200, 200, 200, Path.Direction.CW);
//          設(shè)置為逆時(shí)針
          path.addRect(-200, -200, 200, 200, Path.Direction.CCW);


        // 設(shè)置Path填充模式為非零環(huán)繞規(guī)則
        path.setFillType(Path.FillType.WINDING);
        // 設(shè)置反非零環(huán)繞數(shù)規(guī)則
        // path.setFillType(Path.FillType.INVERSE_WINDING);

        // 繪制Path
        canvas.drawPath(path, mPaint1);               
效果圖

第五組:布爾操作

  • 作用:兩個(gè)路徑Path之間的運(yùn)算
  • 應(yīng)用場(chǎng)景:用簡(jiǎn)單的圖形通過特定規(guī)則合成相對(duì)復(fù)雜的圖形。
  • 具體使用
// 方法1
    boolean op (Path path, Path.Op op)
// 舉例
// 對(duì) path1 和 path2 執(zhí)行布爾運(yùn)算,運(yùn)算方式由第二個(gè)參數(shù)指定
// 運(yùn)算結(jié)果存入到path1中。
    path1.op(path2, Path.Op.DIFFERENCE);


// 方法2
    boolean op (Path path1, Path path2, Path.Op op)
  // 舉例
    // 對(duì) path1 和 path2 執(zhí)行布爾運(yùn)算,運(yùn)算方式由第三個(gè)參數(shù)指定
    // 運(yùn)算結(jié)果存入到path3中。
    path3.op(path1, path2, Path.Op.DIFFERENCE)

之間的運(yùn)算方式(即Path.Op參數(shù))如下


Paste_Image.png

舉例:

   // 為了方便觀察,平移坐標(biāo)系
        canvas.translate(550, 550);

        // 畫兩個(gè)圓
        // 圓1:圓心 = (0,0),半徑 = 100
        // 圓2:圓心 = (50,0),半徑 = 100
        path1.addCircle(0, 0, 100, Path.Direction.CW);
        path2.addCircle(50, 0,100, Path.Direction.CW);

        // 取兩個(gè)路徑的異或集
        path1.op(path2, Path.Op.XOR);
        // 畫出路徑
        canvas.drawPath(path1, mPaint1);
效果圖

4. 貝賽爾曲線

  • 定義:計(jì)算曲線的數(shù)學(xué)公式
  • 作用:計(jì)算并表示曲線

任何一條曲線都可以用貝塞爾曲線表示

  • 具體使用:貝塞爾曲線可通過1數(shù)據(jù)點(diǎn)和若干個(gè)控制點(diǎn)描述
  1. 數(shù)據(jù)點(diǎn):指路徑的起始點(diǎn)和終止點(diǎn);
  2. 控制點(diǎn):決定了路徑的彎曲軌跡;
  3. n+1階貝塞爾曲線 = 有n個(gè)控制點(diǎn);
  4. (1階 = 一條直線,高階可以拆解為多條低階曲線)

Canvas提供了畫二階 & 三階貝塞爾曲線的方法,下面是具體方法:


// 繪制二階貝塞爾曲線
//  (x1,y1)為控制點(diǎn),(x2,y2)為終點(diǎn)
quadTo(float x1, float y1, float x2, float y2)
//  (x1,y1)為控制點(diǎn)距離起點(diǎn)的偏移量,(x2,y2)為終點(diǎn)距離起點(diǎn)的偏移量
rQuadTo(float x1, float y1, float x2, float y2)

// 繪制三階貝塞爾曲線
// (x1,y1),(x2,y2)為控制點(diǎn),(x3,y3)為終點(diǎn)
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
// (x1,y1),(x2,y2)為控制點(diǎn)距離起點(diǎn)的偏移量,(x3,y3)為終點(diǎn)距離起點(diǎn)的偏移量
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

此處只簡(jiǎn)單介紹貝塞爾曲線,想詳細(xì)理解可以參考這篇文章。


5. 總結(jié)

通過閱讀本文,相信你已經(jīng)全面了解Path類的使用。Carson帶你學(xué)Android自定義View文章系列:
Carson帶你學(xué)Android:自定義View基礎(chǔ)
Carson帶你學(xué)Android:一文梳理自定義View工作流程
Carson帶你學(xué)Android:自定義View繪制準(zhǔn)備-DecorView創(chuàng)建
Carson帶你學(xué)Android:自定義View Measure過程
Carson帶你學(xué)Android:自定義View Layout過程
Carson帶你學(xué)Android:自定義View Draw過程
Carson帶你學(xué)Android:手把手教你寫一個(gè)完整的自定義View
Carson帶你學(xué)Android:Canvas類全面解析
Carson帶你學(xué)Android:Path類全面解析


歡迎關(guān)注Carson_Ho的簡(jiǎn)書

不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度。


請(qǐng)點(diǎn)贊!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容