Android控件架構(gòu)
View的測量與繪制
ViewGroup的測量與繪制
自定義控件的三種方式
事件的攔截機(jī)制
3.1 Android控件架構(gòu)
每個控件在界面中占據(jù)一塊矩形的區(qū)域,控件大致可以分為兩類:ViewGroup控件與View控件缸沃;ViewGroup作為父控件可以包含多個View控件妒貌,負(fù)責(zé)下層控件的測量與繪制袱贮,并傳遞交互事件
Android界面的架構(gòu)圖
每個Activity都包含一個Window對象悔橄,Window對象由PhoneWindow實(shí)現(xiàn)缤底;PhoneWindow將一個DecorView設(shè)置為整個應(yīng)用窗口的根View扁耐;DecorView包含了TitleView和ContentView
3.2 View的測量
Android提供了一個MeasureSpec類潦蝇,通過它來測量View款熬。MeasureSpec是一個32位的int值,高2位是測量的模式攘乒,低30位是測量的大邢团!;測量的模式分為三種:
1.EXACTLY:精確值模式(默認(rèn)模式)將控件的“l(fā)ayout_height”则酝,"layout_width"屬性指定為具體值的時候就是EXACTLY模式
2.AT_MOST:最大值模式當(dāng)寬度高度指定為“wrap_content”時殉簸,控件大小一般隨控件的子空間或內(nèi)容的變化而變化,此時控件的尺寸不能超過父控件允許的最大尺寸
3.UNSPECIFIED:不指定其大小測量模式 總結(jié):View的onMeasure()方法只支持EXACTLY模式,所以如果要讓自定義View支持"wrap_content"屬性就要重寫onMeasure()方法來指定wrap_content時的大小般卑。
源碼分析:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
進(jìn)入onMeasure();方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
我們可以看到源代碼是通過setMeasuredDimension來測量大小的
代碼示例
package com.example.view;
import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by 小新 on 2016/6/4.
*/
public class Myview extends View {
public Myview(Context context) {
super(context);
}
public Myview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Myview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasure(widthMeasureSpec),heightMeasure(heightMeasureSpec));
}
private int heightMeasure(int heightMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if(specMode==MeasureSpec.EXACTLY){
result=specSize;
}else{
result=200;
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result,specSize);
}
}
return result;
}
private int widthMeasure(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if(specMode==MeasureSpec.EXACTLY){
result=specSize;
}else{
result=200;
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result,specSize);
}
}
return result;
}
}
這樣當(dāng)我們自定義寬高為"wrap_content的時候"默認(rèn)的大小是200px武鲁;不設(shè)置onMeasure()方法的時候我們使用“wrap_content”默認(rèn)的大小是充滿父控件