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

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

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è)圓形放大一下可以看到效果


抗鋸齒依賴算法實(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填充模式。

4.setStrokeWidth
設(shè)置描邊的寬度,在畫筆在STROKE和FILL_AND_STROKE時(shí)使用。
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(20);
canvas.drawCircle(200, 200, 50, paint);

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

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)繪制可以通過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);

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)

與多點(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);

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

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

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

另外繪制橢圓還有其他重載方法,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);

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è)三角形。

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

path.arcTo(rect, -90, 90, false);

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

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方式如果兩個(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。