前言
根據(jù)Gcssloop所學(xué)習(xí)的自定義View整理與筆記。
一、自定義View流程

簡化版
二、自定義View的代碼超級基礎(chǔ)框架
public class MyView extends View {
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
//TODO 各種初始化內(nèi)容
private void initView() {
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//TODO 在這里進(jìn)行繪圖操作
}
// @Override
// protected void dispatchDraw(Canvas canvas) {
// super.dispatchDraw(canvas);
// }
}
onDraw、dispatchDraw區(qū)別
- onDraw()的意思是繪制視圖自身
dispatchDraw()是繪制子視圖
- 無論是View還是ViewGroup對它們倆的調(diào)用順序都是onDraw()->dispatchDraw()
- 在繪制View控件時(shí),需要重寫onDraw()函數(shù),在繪制ViewGroup時(shí),需要重寫dispatchDraw()函數(shù)。
三、繪制流程
1.** 初始化畫筆**
//TODO 各種初始化內(nèi)容
private void initView() {
paint = new Paint();
paint.setColor(Color.RED);//畫筆顏色為紅色
paint.setStyle(Paint.Style.STROKE);//畫筆模式為描邊
paint.setStrokeWidth(5f);//畫筆寬度為5px
paint.setAntiAlias(true); //是否使用抗鋸齒功能
}
2.繪制內(nèi)容
@Overrideprotected
void onDraw(Canvas canvas) {
super.onDraw(canvas);
//TODO 在這里進(jìn)行繪圖操作
//繪制底色
canvas.drawColor(Color.BLACK);
//在坐標(biāo)(200,500)的位置繪制一個(gè)點(diǎn)
canvas.drawPoint(200, 500, paint);
//在這些坐標(biāo)位置繪制多個(gè)點(diǎn)
canvas.drawPoints(new float[]{
200, 200,
300, 300,
400, 400
}, paint);
//繪制一條起點(diǎn)為(10,10),終點(diǎn)為(100,600)的直線
canvas.drawLine(10, 10, 100, 600, paint);
//繪制一組線
canvas.drawLines(new float[]{
0, 0, 0, 400,
0, 0, 500, 0
}, paint);
//繪制矩形
//第一種方式
canvas.drawRect(315,115,345,145,paint);
//第二種方式
Rect rect = new Rect(360, 115, 390, 145);
canvas.drawRect(rect,paint);
//第三種方式
RectF rectF = new RectF( 335.5f, 160F,370.5f, 170.6f);
canvas.drawRect(rectF,paint);
}

效果圖
四、 繪制一些其他形狀
- 圓角矩形
// 第一種
RectF rectF = new RectF(100,100,800,400);
//drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)
canvas.drawRoundRect(rectF,30,30,paint);
// 第二種,API21以上可用
canvas.drawRoundRect(100,100,800,400,30,30,paint);
** rx,ry的理解**

圓角矩形的角實(shí)際上不是一個(gè)正圓的圓弧,而是橢圓的圓弧,這里的兩個(gè)參數(shù)實(shí)際上是橢圓的兩個(gè)半徑
在rx為寬度的一半,ry為高度的一半時(shí),剛好是一個(gè)橢圓,通過上面我們分析的原理推算一下就能得到,而當(dāng)rx大于寬度的一半,ry大于高度的一半時(shí),實(shí)際上是無法計(jì)算出圓弧的,所以drawRoundRect對大于該數(shù)值的參數(shù)進(jìn)行了限制(修正),凡是大于一半的參數(shù)均按照一半來處理
- 橢圓
// 第一種
RectF rectF = new RectF(100,100,800,400);
canvas.drawOval(rectF,paint);
// 第二種
canvas.drawOval(100,100,800,400,paint);

橢圓原理
- 圓
// 繪制一個(gè)圓心坐標(biāo)在(500,500),半徑為400 的圓。
canvas.drawCircle(500,500,400,paint);
- 圓弧
// 第一種
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}
// 第二種
public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
startAngle :開始角度
sweepAngle:掃過角度
useCenter:是否使用中心
demo來一個(gè)吧O(∩_∩)O~
RectF rectF = new RectF(100, 100, 400, 300);
// 繪制背景矩形
paint.setColor(Color.GRAY);
canvas.drawRect(rectF, paint);
// 繪制圓弧
paint.setColor(Color.BLUE);
canvas.drawArc(rectF, 0, 60, false, paint);
RectF rectF2 = new RectF(100, 400, 400, 600);
// 繪制背景矩形
paint.setColor(Color.GRAY);
canvas.drawRect(rectF2, paint);
// 繪制圓弧
paint.setColor(Color.BLUE);
canvas.drawArc(rectF2, 0, 60, true, paint);
效果圖:

五、畫個(gè)餅圖
要點(diǎn):不斷改變startAngle和sweepAngle的值就OK啦,直接舉栗子

餅圖效果圖
public class MyView extends View {
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private Paint paint;
private int[] startAngle = new int[6];
private int[] color = {Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA};
//TODO 各種初始化內(nèi)容
private void initView() {
paint=new Paint();
paint.setColor(Color.RED);//畫筆顏色為紅色
paint.setStyle(Paint.Style.FILL);//畫筆模式為描邊
paint.setStrokeWidth(5f);//畫筆寬度為5px
paint.setAntiAlias(true); //是否使用抗鋸齒功能
for (int i = 0; i < 5; i++) {
startAngle[i] = i * 60 + i;
}
startAngle[5] = 360;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//TODO 在這里進(jìn)行繪圖操作
//移動到屏幕(200,300)的位置,下一篇會具體講解的
canvas.translate(200, 300);
RectF rect = new RectF(-100, -100, 200, 200);
for (int i = 0; i < 5; i++) {
paint.setColor(color[i]);
canvas.drawArc(rect, startAngle[i], startAngle[i+1]-startAngle[i], true, paint);
}
}}
六、canvas的各種方法
[之后會講解的,這里只提一下O(∩_∩)O~]
drawColor, drawRGB, drawARGB //使用單一顏色填充整個(gè)畫布
drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc//依次為 點(diǎn)、線、矩形、圓角矩形、橢圓、圓、圓弧
drawBitmap, drawPicture//繪制位圖和圖片
drawText, drawPosText, drawTextOnPath//依次為 繪制文字、繪制文字時(shí)指定每個(gè)文字位置、根據(jù)路徑繪制文字
drawPath//繪制路徑,繪制貝塞爾曲線時(shí)也需要用到該函數(shù)
drawVertices, drawBitmapMesh//通過對頂點(diǎn)操作可以使圖像形變,drawVertices直接對畫布作用、 drawBitmapMesh只對繪制的Bitmap作用
clipPath, clipRect//畫布剪裁,設(shè)置畫布的顯示區(qū)域
save, restore, saveLayerXxx, restoreToCount, getSaveCount//依次為 保存當(dāng)前狀態(tài)、 回滾到上一次保存的狀態(tài)、 保存圖層狀態(tài)、 回滾到指定狀態(tài)、 獲取保存次數(shù)
translate, scale, rotate, skew//畫布變換,依次為 位移、縮放、 旋轉(zhuǎn)、錯(cuò)切
getMatrix, setMatrix, concat//實(shí)際上畫布的位移,縮放等操作的都是圖像矩陣Matrix, 只不過Matrix比較難以理解和使用,故封裝了一些常用的方法。