Android群英傳---View、ViewGroup的測量和繪製
View的測量
系統通過onMeasure()
對View進行測量
1.系統提供MeasureSpec
類幫助測量View
- MeasureSpec是
32bit
的int值,期中高2bit
為測量的模式,低30位
為測量的大小。用於提高效率
測量的模式如下:
1. ++EXACTLY++
精確值模式:
控制元件屬性width or height
設定為具體數值,如100dp
,或者指定為match_parent
屬性,就是該模式。
2. ++AT_MOST++
最大值模式:
控制元件屬性width or height
設定為wrap_content
。此時控制元件的尺寸不超過父控制元件允許的最大尺寸即可。
3. ++UNSPECIFIED++
不指定大小的測量模式,View想多大就多大,通常情況下載繪製自定義View時才會使用。
- View類預設的
onMeasure()
方法只支援EXACTLY
,。 - 自定義控制元件想使用
wrap_content
就必須重寫onMeasure()
來指定wrap_content
時的大小。
*
2. View測量例項
onMeasure()如下
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
可以發現,本質上系統最終會呼叫setMeasuredDimension(int measuredWidth, int measuredHeight)
,將測量之後的寬高值設定進去。所以重寫onMeasure()
最終是將測量後的寬高值設定給該方法。
因此重寫onMeasure()方法如下
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
- 其中
measureWidth
ormeasureHeight
用來測量高度和寬度,程式碼如下:
//測量寬度
private int measureWidth(int widthMeasureSpec){
//提取出模式以及尺寸
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
int alone = 0;
//精確值模式: 例如200dp or match_parent
if(specMode == MeasureSpec.EXACTLY){
alone = specSize;
}else{
alone = 200; //?????
//最大值模式: wrap_parent
if(specMode == MeasureSpec.AT_MOST){
alone = Math.min(alone, specSize);
}
}
return alone;
}
//測量高度
private int measureHeight(int heightMeasureSpec){
//提取出模式以及尺寸
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
int result = 0;
//精確值模式: 例如200dp or match_parent
if(specMode == MeasureSpec.EXACTLY){
result = specSize;
}else{
result = 200; //?????
//最大值模式: wrap_parent
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
其中
result = 200;
表示在wrap_content
屬性的時候獲得預設的200px
作為長度
View的繪製
通常通過繼承View並且重寫它的onDraw()
方法來完成繪圖。
onDraw()
中有一個引數,就是Canvas canvas
物件。使用這個Canvas
物件就可以進行繪圖了,其他物件需要用程式碼建立。
Canvas canvas = new Canvas(bitmap);
為什麼要傳入bitmap?
不傳入bitmap也不會報錯,但是不要這麼做。bitmap
是用來儲存所有繪製在Canvas
上的畫素資訊。之後所有的Canvas.drawXXX
都在該bitmap上。
Bitmap bitmap1 = Bitmap.createBitmap(new int[]{R.color.colorAccent, R.color.colorPrimary}, 200, 100, Bitmap.Config.RGB_565);
canvas.drawBitmap(bitmap1, 0,0,null);
ViewGroup的測量
ViewGroup用於管理子View,在控制顯示大小時,如果ViewGroup設定為wrap_content時,就需要遍歷所有子View來確定大小
遍歷子View就是呼叫其onMeasure方法進行測量。View擺放位置就是呼叫ViewGroup的layout方法,其內部遍歷子View的layout方法來指定具體位置。
自定義ViewGroup
通常重寫onLayout()
控制子View
的顯示位置。
如果支援wrap_content
,必須重寫onMeasure()
ViewGroup一般不需要繪製
設定ViewGroup背景顏色的時候,呼叫onDraw()
方法
ViewGroup會呼叫dispatchDraw()
方法來繪製子View,其通過遍歷子View,並且呼叫其繪製方法。