android 自定义view控件,Android 自定义View——自定义View控件
Android給我們提供了大量的View控件,但這還是遠遠滿足不了我們的要求,有時候開發(fā)所需要的控件形式是在Android提供的控件中是不存在,這就需要我們自己去定義一個。那么如何自定義控件?
學(xué)習(xí)自定義控件,首先要先掌握Canvas類的使用。
Canvas
Canvas, 我們稱之為“畫布“,主要適用于繪制View的。
Canvas中提供了大量繪制圖形的方法:
繪制扇形:
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint):
第一個參數(shù)RectF對象,指定扇形的區(qū)域;第二個參數(shù)是起始角度;第三個參數(shù)是旋轉(zhuǎn)角度,順時針旋轉(zhuǎn);第四個參數(shù)是是否填充,true為填充,false為不填充,也就是為一條弧線;第五個參數(shù)是繪制圖形的畫筆對象Paint。
RectF:
通過RectF(float left, float top, float right, float bottom)構(gòu)造器創(chuàng)建RectF對象,我們通過下圖理解各個參數(shù)的含義,RectF對象指代的就是一個矩形區(qū)域。我們通過這四個參數(shù)構(gòu)建矩形區(qū)域。
Paint:
是繪制所有圖形所用到的一個畫筆,我們在稍后講解。
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
這個是將扇形區(qū)域左,上,右,下邊的坐標直接輸入,而不是通過RectF對象。其他參數(shù)同上。
繪制圓形:
drawCircle(float cx, float cy, float radius, Paint paint)
第一、二個參數(shù)是指圓形的x, y坐標; 第三個參數(shù)是半徑; 第四個參數(shù)是畫筆Paint對象。
繪制直線:
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
兩點確定一條直線,第一、二參數(shù)是起始點的坐標;第三、四參數(shù)是結(jié)束點的坐標;第五個參數(shù)畫筆Paint對象。
drawLines(float[] pts, Paint paint)
多個點確定一條直線,第一個參數(shù)是點的數(shù)組;第二個參數(shù)是畫筆Paint對象。
drawLines(float[] pts, int offset, int count, Paint paint)
繪制橢圓:
drawOval(float left, float top, float right, float bottom, Paint paint)
前四個參數(shù)是橢圓的左,上,右,下邊的坐標,第五個是畫筆Paint對象。
drawOval(RectF oval, Paint paint)
第一個參數(shù)是RectF對象, 第二個參數(shù)是畫筆Paint對象。
繪制矩形:
drawRect(RectF rect, Paint paint)
第一個參數(shù)是RectF對象, 第二個參數(shù)是畫筆Paint對象。
繪制點:
drawPoint(float x, float y, Paint paint)
第一、二個參數(shù)點的坐標,第三個參數(shù)為Paint對象。
渲染文本:
drawText(String text, float x, floaty, Paint paint)
drawText(CharSequence text, int start, int end, float x, float y, Paint paint)
drawText(char[] text, int index, int count, float x, float y, Paint paint)
drawText(String text, int start, int end, float x, float y, Paint paint)
Canvas中還給我們提供了很多繪制其他圖形的方法,這里我們不在一一列舉。我們來看一下Paint”畫筆“。
Paint
Paint是用于繪制的畫筆,Canvas就像是我們的畫紙,我們需要筆才可以完成一整幅圖。Paint中為我們提供了很多設(shè)置的方法(我們這里只列舉常用的方法):
setARGB(int a, int r, int g, int b)
設(shè)置 Paint對象顏色,參數(shù)一為alpha透明值
setAlpha(int a)
設(shè)置alpha不透明度,范圍為0~255
setAntiAlias(boolean aa)
是否抗鋸齒,這個一般是都要設(shè)置的。
setColor(int color)
設(shè)置顏色,這里Android內(nèi)部定義的有Color類包含了一些常見顏色定義
setTextScaleX(float scaleX)
設(shè)置文本縮放倍數(shù),1.0f為原始
setTextSize(float textSize)
設(shè)置字體大小
setUnderlineText(booleanunderlineText)
設(shè)置下劃線
setStrokeCap(Paint.Cap cap)
當畫筆樣式為STROKE或FILL_OR_STROKE時,設(shè)置筆刷的圖形樣式,如圓形樣式 Cap.ROUND,或方形樣式Cap.SQUARE
setSrokeJoin(Paint.Join join)
設(shè)置繪制時各圖形的結(jié)合方式,如平滑效果等
自定義View
現(xiàn)在我們來使用Canvas類自定義一個View控件。自定義控件步驟如下:
1. 自定義View,首先定義一個MyView類繼承View類。
2. 重寫View的兩個構(gòu)造器。
View是包含四個構(gòu)造器的,我們必須重寫MyWidgetView(Context context, AttributeSet attrs)構(gòu)造器,因為該構(gòu)造器的第二個參數(shù)是與xml布局文件相聯(lián)系的,如果沒有重寫該構(gòu)造器,將不能在布局中使用該控件。這里我們重寫他的兩個構(gòu)造器:
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
3. 重寫onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,定義控件的尺寸:寬度和高度。在布局中使用該控件時會會傳入控件的尺寸,只有當傳入尺寸之后且調(diào)用onMesure之后,控件才會有寬度和高度。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//設(shè)置寬和高
}
重寫onDraw(Canvas canvas)方法,我們在該方法中定義繪制View,當我們在Activity或其他地方使該控件時, UI主線程會調(diào)用onDraw方法繪制。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
onDraw(Canvas canvas)方法中傳入了一個Canvas對象,我們在定義控件時,使用Canvas繪制。
繪制時鐘
這里我們通過繪制一個時鐘來鞏固一下自定義控件以及Canvas類的使用。
1. 定義一個MyView繼承View。
2. 重寫MyView(Context context, AttributeSet attrs)構(gòu)造器。
3. 在重寫onMeasureh和onDraw方法。
4. 在onDraw方法中繪制。
大體步驟就是這樣,我們先貼代碼,逐步講解:
public class MyView extends View {
private int width;//設(shè)置高
private int height;//設(shè)置高
private Paint mPaintLine;//定義一個繪制直線的畫筆
private Paint mPaintSecondLine;//定義一個繪制直線的畫筆
private Paint mPaintInterCircle;//定義一個繪制圓的畫筆
private Paint mPaintOutSideCircle;//定義一個繪制圓的畫筆
private Paint mPaintText;//定義一個繪制文字的畫筆
private Calendar mCalendar;//創(chuàng)建一個時間類
private static final int NEED_INVALIDATE=0X6666;
//操作UI主線程
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case NEED_INVALIDATE:
//跟新時間
mCalendar=Calendar.getInstance();
invalidate();
sendEmptyMessageDelayed(NEED_INVALIDATE,1000);
break;
}
}
};
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化畫直線的畫筆
mPaintLine = new Paint();
mPaintLine.setAntiAlias(true);//消除鋸齒
mPaintLine.setColor(Color.GRAY);//設(shè)置畫筆顏色
mPaintLine.setStyle(Paint.Style.STROKE);//設(shè)置為空心
mPaintLine.setStrokeWidth(10);//設(shè)置寬度
// 初始化秒針的畫筆
mPaintSecondLine = new Paint();
mPaintSecondLine.setAntiAlias(true);//消除鋸齒
mPaintSecondLine.setColor(Color.GRAY);//設(shè)置畫筆顏色
mPaintSecondLine.setStyle(Paint.Style.STROKE);//設(shè)置為空心
mPaintSecondLine.setStrokeWidth(7);//設(shè)置寬度
//初始化內(nèi)圓的畫筆
mPaintInterCircle = new Paint();
mPaintInterCircle.setAntiAlias(true);//消除鋸齒
mPaintInterCircle.setColor(Color.BLACK);
mPaintInterCircle.setStyle(Paint.Style.STROKE);//設(shè)置為空心
mPaintInterCircle.setStrokeWidth(5);
//初始化外圓的畫筆
mPaintOutSideCircle = new Paint();
mPaintOutSideCircle.setAntiAlias(true);//消除鋸齒
mPaintOutSideCircle.setColor(Color.BLACK);
mPaintOutSideCircle.setStyle(Paint.Style.STROKE);//設(shè)置為空心
mPaintOutSideCircle.setStrokeWidth(10);
//繪制文字的畫筆
mPaintText = new Paint();
mPaintText.setAntiAlias(true);//消除鋸齒
mPaintText.setColor(Color.GRAY);
mPaintText.setStyle(Paint.Style.STROKE);//設(shè)置為空心
mPaintText.setTextAlign(Paint.Align.CENTER);
mPaintText.setTextSize(40);
mPaintText.setStrokeWidth(6);
//初始化日歷
mCalendar = Calendar.getInstance();
//發(fā)送一個消息給UI主線程
handler.sendEmptyMessageDelayed(NEED_INVALIDATE,2000);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);//設(shè)置寬和高
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 主線程自動調(diào)用
canvas.drawCircle(width / 2, height / 2, 300, mPaintInterCircle);
canvas.drawCircle(width / 2, height / 2, 320, mPaintOutSideCircle);
for(int i=1; i<=12;i++){
canvas.save();//保存當前狀態(tài)
canvas.rotate(360 / 12 * i, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 270, mPaintLine);
canvas.drawText("" + i, width / 2, height / 2 - 240, mPaintText);
canvas.restore();//回到save()方法保存的狀態(tài)
}
//繪制分針
int minute= mCalendar.get(Calendar.MINUTE);
float minuteDegree = minute/60f*360;
canvas.save();
canvas.rotate(minuteDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 200, width / 2, height / 2 + 40, mPaintLine);
canvas.restore();
//繪制時針
int hour= mCalendar.get(Calendar.HOUR);
float hourDegree = (hour*60+minute)//(12f*60)*360;
canvas.save();
canvas.rotate(hourDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 170, width / 2, height / 2 + 30, mPaintLine);
canvas.restore();
//繪制秒針
int second = mCalendar.get(Calendar.SECOND);
float secondDegree = second*6;//一秒是6度。
canvas.save();
canvas.rotate(secondDegree, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 220, width / 2, height / 2 + 50, mPaintSecondLine);
canvas.restore();
}
}
繪制兩個圓形嵌套這個很簡單,不用多說。然后繪制刻度,是使用了Canvas畫布的旋轉(zhuǎn),這個很好理解,我們在畫畫的時候,有時候要畫一些比較難的角度,我們都是將畫板旋轉(zhuǎn)而不是我們自己換角度。在繪制時鐘時,我們要繪制時鐘每個時間的刻度,我們可以將要繪制刻度的位置旋轉(zhuǎn)到豎直方向,然后繪制。
for(int i=1; i<=12;i++){
canvas.save();//保存當前狀態(tài)
canvas.rotate(360 / 12 * i, width / 2, height / 2);
canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 270, mPaintLine);
canvas.drawText("" + i, width / 2, height / 2 - 240, mPaintText);
canvas.restore();//回到save()方法保存的狀態(tài)
}
然后繪制時針,分針和秒針,他們都是繪制一條線。然后通過獲取當前的時間將這條線指向?qū)Φ脮r間點,也就是偏轉(zhuǎn)對得角度。這里的偏轉(zhuǎn)我們依然使用畫布的偏轉(zhuǎn)。
以上完成后,我們的時鐘就差不多完成了,但是,我們發(fā)現(xiàn)我們的表并沒有走。實現(xiàn)我們繪制的時鐘轉(zhuǎn)動的方式就是然我們的時鐘每一秒onDraw一次,這樣我們的時鐘正常了。onDraw是UI主線程不斷調(diào)用重繪界面的,因此我們需要使用到Handler,通過發(fā)送一個消息給Handler對象,讓Handler對象在每一秒重繪一次MyView控件。這里重繪不能調(diào)用onDraw()方法額,而要調(diào)用的是invalidate()方法,invalidate()方法中調(diào)用了onDraw()方法。
//操作UI主線程
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case NEED_INVALIDATE:
//跟新時間
mCalendar=Calendar.getInstance();
invalidate();
sendEmptyMessageDelayed(NEED_INVALIDATE,1000);
break;
}
}
};
這樣我們的時鐘也轉(zhuǎn)動了……
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的android 自定义view控件,Android 自定义View——自定义View控件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python pycharm打包_【转】
- 下一篇: android应用控制百度地图,Andr