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

什么是自定義控件

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

紙和筆.jpg

android的繪制跟我們平常的畫畫一樣祝谚,我們在畫畫的時候需要筆和紙宪迟。android開發(fā)中筆就是Paint類,Canvas就是紙交惯。凡是一些設(shè)置畫筆的粗細次泽、畫筆顏色穿仪、透明度都是在Paint類中設(shè)置的,凡是能畫出某種物體比如繪制圓形意荤、矩形啊片、文字都是在canvas里進行完成。
自定義繪制非常容易只需要重寫onDraw方法玖像,將創(chuàng)建好Paint對象傳入canvas中,這里需要注意的是onDraw方法需要super.onDraw方法紫谷,而且android中的坐標系是左上角為(0,0)原點御铃。

 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);

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

未開鋸齒.jpg

開鋸齒.jpg

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

3.setStyle
public void setStyle(Style style)

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

Style樣式.jpg

4.setStrokeWidth

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

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

Canvas基礎(chǔ)

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

canvas可以實現(xiàn)畫布的顏色設(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默認是255增拥。

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

drawPoint方法x啄巧,y分別是設(shè)置點的坐標,點的大小可以用setStrokeWidth方法設(shè)置大小掌栅。

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

點.jpg

多點繪制可以通過drawPoints方法來實現(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è)置點的坐標,設(shè)置為{x1,y1,x2,y2...}猾封,offset是跳過數(shù)值的個數(shù)(一個點有兩個數(shù))澄耍。count代表繪制數(shù)字的個數(shù)。

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

startX齐莲、startY、stopX磷箕、stopY分別代表坐標的起始位置以及終止位置选酗。
繪制多條直線

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

與多點繪制相似,可以利用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方法可以繪制矩形我們可以通過矩形的四個點傳值也可以通過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è)置圓心點的坐標盛泡,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ù)邊界點繪制橢圓。

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.直線路徑

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

public void moveTo(float x, float y) 

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

public void lineTo(float x, float y)

lineTo方法是根據(jù)起始點設(shè)置終點饼齿。

public void close()

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

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

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

路徑.png

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

這個方法和 Canvas.drawArc() 比起來僚楞,少了一個參數(shù) useCenter,而多了一個參數(shù) forceMoveTo枉层,forceMoveTo是否連線到弧形起點泉褐。

        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順時針,CCW逆時針鸟蜡。無論是順時針逆時針膜赃,僅僅是方向不同,這里后邊會介紹矩欠,其他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 (默認值)顯示方向相交的內(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方式如果兩個圖形的path方向相同悠夯,即方向不想交癌淮,則可以全部顯示,若方向不同沦补,就產(chǎn)生了相交區(qū)域乳蓄。
EVEN_ODD與WINDING不同同方向效果一致。
INVERSE_WINDING與INVERSE_EVEN_ODD與剛剛介紹的兩個相反夕膀。

5.重置路徑

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

void reset()
void rewind()

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耻煤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子准颓,更是在濱河造成了極大的恐慌哈蝇,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攘已,死亡現(xiàn)場離奇詭異炮赦,居然都是意外死亡,警方通過查閱死者的電腦和手機样勃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門吠勘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來性芬,“玉大人,你說我怎么就攤上這事剧防∨” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵诵姜,是天一觀的道長汽煮。 經(jīng)常有香客問我,道長棚唆,這世上最難降的妖魔是什么暇赤? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮宵凌,結(jié)果婚禮上鞋囊,老公的妹妹穿的比我還像新娘。我一直安慰自己瞎惫,他們只是感情好溜腐,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瓜喇,像睡著了一般挺益。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乘寒,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天望众,我揣著相機與錄音,去河邊找鬼伞辛。 笑死烂翰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚤氏。 我是一名探鬼主播甘耿,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竿滨!你這毒婦竟也來了佳恬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤姐呐,失蹤者是張志新(化名)和其女友劉穎殿怜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曙砂,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡头谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸠澈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柱告。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡截驮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出际度,到底是詐尸還是另有隱情葵袭,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布乖菱,位于F島的核電站坡锡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窒所。R本人自食惡果不足惜鹉勒,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吵取。 院中可真熱鬧禽额,春花似錦、人聲如沸皮官。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捺氢。三九已至藻丢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讯沈,已是汗流浹背郁岩。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓奕锌,卻偏偏與公主長得像山害,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子冰木,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

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