自定義控件——繪制基礎(chǔ)(一)

什么是自定義控件

自定義控件有三個(gè)點(diǎn),布局繪制和觸摸反饋。接下來的章節(jié)我們先說繪制,繪制就是在控件上顯示需要我們用代碼控制繪制細(xì)節(jié),顯示系統(tǒng)自帶控件顯示不出的內(nèi)容,不管是多復(fù)雜的顯示我們能夠通過自定義控件繪制出來。

紙和筆.jpg

android的繪制跟我們平常的畫畫一樣,我們在畫畫的時(shí)候需要筆和紙。android開發(fā)中筆就是Paint類,Canvas就是紙。凡是一些設(shè)置畫筆的粗細(xì)、畫筆顏色、透明度都是在Paint類中設(shè)置的,凡是能畫出某種物體比如繪制圓形、矩形、文字都是在canvas里進(jìn)行完成。
自定義繪制非常容易只需要重寫onDraw方法,將創(chuàng)建好Paint對象傳入canvas中,這里需要注意的是onDraw方法需要super.onDraw方法,而且android中的坐標(biāo)系是左上角為(0,0)原點(diǎn)。

 private Paint paint = new Paint();

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(10, 10, 100, 100, paint);
    }

Paint相關(guān)方法

1.setColor
public void setColor(@ColorInt int color)

設(shè)置畫筆的顏色,向下邊這樣。

paint.setColor(Color.YELLOW);
canvas.drawRect(10, 10, 100, 100, paint);
黃色的矩形.jpg
2.setAntiAlias
public void setAntiAlias(boolean aa)

一些不規(guī)則的圖形例如文字,圓形需要打開抗鋸齒功能讓邊緣更平滑。我們可以通過setAntiAlias方法可以設(shè)置是否使用抗鋸齒,也可以在Paint構(gòu)造函數(shù)中傳入ANTI_ALIAS_FLAG

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
paint.setAntiAlias(true);

下邊繪制一個(gè)圓形放大一下可以看到效果

未開鋸齒.jpg

開鋸齒.jpg

抗鋸齒依賴算法實(shí)現(xiàn)的,通過修改邊緣處的顏色,讓圖形有了平滑的感覺。

3.setStyle
public void setStyle(Style style)

setStyle方法設(shè)置填充樣式,對文字以及圖形都有效。樣式一共有三種,Paint.Style.FILL填充模式,Paint.Style.STROKE描邊模式,以及Paint.Style.FILL_AND_STROKE兩個(gè)模式一起使用,默認(rèn)情況下是FILL填充模式。

Style樣式.jpg

4.setStrokeWidth

設(shè)置描邊的寬度,在畫筆在STROKE和FILL_AND_STROKE時(shí)使用。

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
canvas.drawCircle(200, 200, 50, paint);
setStrokeWidth.jpg

Canvas基礎(chǔ)

1.畫布顏色設(shè)置

canvas可以實(shí)現(xiàn)畫布的顏色設(shè)置,通過以下方法實(shí)現(xiàn)。

public void drawColor(@ColorInt int color)
public void drawARGB(int a, int r, int g, int b)
public void drawRGB(int r, int g, int b)

根據(jù)drawColor方法可以知道,我們需要傳入8位的顏色值,drawARGB傳入A、R、G、B的顏色取值0~255范圍。drawRGB函數(shù)只傳入R、G、B,Alpha默認(rèn)是255。

canvas.drawColor(Color.parseColor("#FF0000"));
canvas.drawRGB(255,0,0);
canvas.drawARGB(255,255,0,0);
畫布設(shè)置.png
2.繪制點(diǎn)
public void drawPoint(float x, float y, @NonNull Paint paint)

drawPoint方法x,y分別是設(shè)置點(diǎn)的坐標(biāo),點(diǎn)的大小可以用setStrokeWidth方法設(shè)置大小。

paint.setStrokeWidth(80);
canvas.drawPoint(120, 120, paint);

點(diǎn).jpg

多點(diǎn)繪制可以通過drawPoints方法來實(shí)現(xiàn)。

public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
            @NonNull Paint paint)
            
public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint)

這里pts是設(shè)置點(diǎn)的坐標(biāo),設(shè)置為{x1,y1,x2,y2...},offset是跳過數(shù)值的個(gè)數(shù)(一個(gè)點(diǎn)有兩個(gè)數(shù))。count代表繪制數(shù)字的個(gè)數(shù)。

paint.setColor(Color.RED);
paint.setStrokeWidth(80);
float[] pts = {50, 50, 100, 100, 200, 200, 300, 300};
canvas.drawPoints(pts, 2/* 跳過兩個(gè)數(shù),即前兩個(gè) 0 */, 6/* 一共繪制 6 個(gè)數(shù)(3 個(gè)點(diǎn)) */, paint);
drawPoints.jpg
3.繪制直線
public void drawLine(float startX, float startY, float stopX, float stopY,
            @NonNull Paint paint)

startX、startY、stopX、stopY分別代表坐標(biāo)的起始位置以及終止位置。
繪制多條直線

public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
            @NonNull Paint paint)
            
public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint)
直線.png

與多點(diǎn)繪制相似,可以利用drawLines方法繪制多條線段。

4.繪制矩形
public void drawRect(@NonNull RectF rect, @NonNull Paint paint)

public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)

利用drawRect方法可以繪制矩形我們可以通過矩形的四個(gè)點(diǎn)傳值也可以通過RectF、Rect傳值。

paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(100, 100, 200, 200, paint);
矩形.jpg
5.繪制圓角矩形
public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)

利用drawRoundRect方法可以繪制出帶有圓角的矩形參數(shù)RectF設(shè)置繪制的矩形,rx、ry分別代表x軸和y軸的半徑。

圓角矩形.png

6.繪制圓形
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint)

cx和cy分別設(shè)置圓心點(diǎn)的坐標(biāo),radius設(shè)置圓形半徑。

canvas.drawCircle(100, 100, 30, paint);
圓形.png
7.繪制橢圓
public void drawOval(@NonNull RectF oval, @NonNull Paint paint)

drawOval是繪制橢圓的方法,根據(jù)矩形oval區(qū)域繪制出橢圓。

        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint2.setStyle(Paint.Style.STROKE);
        paint2.setColor(Color.RED);
        paint2.setStrokeWidth(5);
        RectF rect = new RectF(100, 100, 400, 300);
        canvas.drawOval(rect, paint);
        canvas.drawRect(rect, paint2);

橢圓.png

另外繪制橢圓還有其他重載方法,drawOval(float left, float top, float right, float bottom, @NonNull Paint paint)根據(jù)邊界點(diǎn)繪制橢圓。

8.繪制弧形
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            @NonNull Paint paint)

弧是橢圓的一部分,橢圓又是根據(jù)矩形生成的,所以弧形也是根據(jù)矩形而來。
這里oval是矩形區(qū)域,startAngle是弧形的起始弧度,sweepAngle是弧形劃過的角度;useCenter 表示是否連接到圓心,如果不連接到圓心,就是弧形,如果連接到圓心,就是扇形。

        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint2.setStyle(Paint.Style.STROKE);
        paint2.setColor(Color.RED);
        paint2.setStrokeWidth(5);
        RectF rect = new RectF(100, 100, 400, 300);
        canvas.drawArc(rect, 0, 90, true, paint);
        canvas.drawArc(rect, 90, 180, false, paint2);
弧線.png

Path路徑

在android開發(fā)中通過canvas繪制路徑

void drawPath(Path path, Paint paint)

接下來看看path下有哪些方法。

1.直線路徑

畫直線一般需要三個(gè)函數(shù)

public void moveTo(float x, float y) 

x,y設(shè)置起始點(diǎn)的位置。由當(dāng)前位置 (0, 0) 移動(dòng)致 (x, y)

public void lineTo(float x, float y)

lineTo方法是根據(jù)起始點(diǎn)設(shè)置終點(diǎn)。

public void close()

如果前邊的劃線沒有形成閉環(huán)那么調(diào)用close方法可以首尾連接起來。當(dāng)需要填充圖形時(shí)(即 Paint.Style 為 FILL 或 FILL_AND_STROKE),Path 會(huì)自動(dòng)封閉子圖形。后邊會(huì)有介紹。

        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        Path path = new Path();
        path.moveTo(150, 150);//移動(dòng)到(150,150)初始化為原點(diǎn)
        path.lineTo(50, 250);//第一條線
        path.lineTo(250, 250);//第二條線
        path.close();
        canvas.drawPath(path, paint);

close方法調(diào)用后形成一個(gè)閉環(huán)形成一個(gè)三角形。

路徑.png

2.弧線路徑
public void arcTo(@NonNull RectF oval, float startAngle, float sweepAngle,
                      boolean forceMoveTo)

這個(gè)方法和 Canvas.drawArc() 比起來,少了一個(gè)參數(shù) useCenter,而多了一個(gè)參數(shù) forceMoveTo,forceMoveTo是否連線到弧形起點(diǎn)。

        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);

        RectF rect = new RectF(200, 200, 300, 300);
        Path path = new Path();

        path.moveTo(100, 100);
        path.lineTo(150, 150);
        path.arcTo(rect, -90, 90, true);
        canvas.drawPath(path, paint);
forceMoveTo為true.png
path.arcTo(rect, -90, 90, false);
forceMoveTo為false.png.png
3.addXXX系列方法

添加圓形

public void addCircle(float x, float y, float radius, @NonNull Direction dir)

Direction是指路徑方向CW順時(shí)針,CCW逆時(shí)針。無論是順時(shí)針逆時(shí)針,僅僅是方向不同,這里后邊會(huì)介紹,其他addxxx方法也類似。
添加橢圓

public void addOval(@NonNull RectF oval, @NonNull Direction dir)

添加矩形

public void addRect(@NonNull RectF rect, @NonNull Direction dir)

添加圓角矩形

public void addRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Direction dir)
4.填充方式
public void setFillType(@NonNull FillType ft)
  • WINDING (默認(rèn)值)顯示方向相交的內(nèi)容
  • EVEN_ODD 相交的地方填充
  • INVERSE_WINDING
  • INVERSE_EVEN_ODD
        path.setFillType(Path.FillType.WINDING);
        path.addCircle(200, 200, 100, Path.Direction.CW);
        path.addCircle(290, 200, 100, Path.Direction.CW);
        canvas.drawPath(path, paint);
WINDING相同方向.jpg
        path.setFillType(Path.FillType.WINDING);
        path.addCircle(200, 200, 100, Path.Direction.CW);
        path.addCircle(290, 200, 100, Path.Direction.CCW);
        canvas.drawPath(path, paint);

WINDING不同同方向.png

WINDING方式如果兩個(gè)圖形的path方向相同,即方向不想交,則可以全部顯示,若方向不同,就產(chǎn)生了相交區(qū)域。
EVEN_ODD與WINDING不同同方向效果一致。
INVERSE_WINDING與INVERSE_EVEN_ODD與剛剛介紹的兩個(gè)相反。

5.重置路徑

當(dāng)我們需要繪制一條全新的路徑的時(shí)候,可以重置路徑的對象,這樣我們就可以不需要重新定義路徑的對象了。

void reset()
void rewind()

reset會(huì)保留當(dāng)前的數(shù)據(jù)結(jié)構(gòu),會(huì)清除FillType,rewind會(huì)清除數(shù)據(jù)空間,但不會(huì)清除FillType。

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

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

  • HenCoder 原文 關(guān)鍵點(diǎn) 自定義繪制方法的重寫,其中最常用的是onDraw 繪制的關(guān)鍵是Canvas的使用C...
    李小神不偷懶閱讀 659評論 4 1
  • 系列文章之 Android中自定義View(一)系列文章之 Android中自定義View(二)系列文章之 And...
    YoungerDev閱讀 4,630評論 3 11
  • 記錄下自己學(xué)習(xí)自定義View的過程。共勉 首先,在我們創(chuàng)建的自定義View中 重寫onDraw()方法。如下 @O...
    萬有引力丶閱讀 1,082評論 0 1
  • 自定義繪制概述 方法:重寫繪制方法(最常用:onDraw()) 繪制的關(guān)鍵:CanvasCanvas的繪制類方法:...
    NewSalton閱讀 502評論 0 0
  • 最近在跟扔物線大嬸學(xué)自定義控件,其實(shí)許多東西之前都用過的,不過時(shí)間長就忘了,然后這次就系統(tǒng)的復(fù)習(xí)一下,順便記錄下來...
    jeff_sun閱讀 580評論 1 3

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