View工作原理 -- 工作過程 -- measure(1)

View的measure過程

View的measure過程由其measure方法來完成,measure方法是一個final類型的方法,子類不能重寫此方法。在View的measure方法中會去調(diào)用View的onMeasure方法。

View#onMeasure:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasureDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 
                        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

View#getDefaultSize:
public static int getDefaultSize(int size, int measureSpec) {
    int result = size; //size大小由getSuggestedMinimumWidth方法或getSuggestedMinimumHeight方法確定
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch(specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}
  1. 當(dāng)前View的SpecMode為AT_MOSTEXACTLY時,getDefaultSize方法返回的大小就是measureSpec中的specSize,而這個specSize就是View測量后的大小。
  2. 當(dāng)前View的SpecMode為UNSPECIFIED時,getDefaultSize方法返回的大小就是getSuggestedMinimumWidth方法或getSuggestedMinimumHeight方法的返回值。
    分析getSuggestedMinimumWidth方法:
View#getSuggestedMinimumWidth:
protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());

Drawable#getMinimumWidth:
public int getMinimumWidth() {
    final int intrinsicWidth = getIntrinsicWidth();
    return intrinsicWidth > 0 ? intrinsicWidth : 0;
}

(1)如果View沒有設(shè)置背景,那么View的寬度為mMinWidth。
mMinWidth對應(yīng)于android:minWidth這個屬性所指定的值,如果不指定則默認(rèn)為0。
(2)如果View設(shè)置了背景,那么View的寬度為max(mMinWidth, mBackground.getMinimumWidth())。
Drawable#getMinimumWidth方法返回的是Drawable的原始寬度,前提是這個Drawable有原始寬度,否則就返回0。如ShapeDrawable無原始寬/高,而BitmapDrawable有原始寬/高(圖片的尺寸)。

從getDefaultSize方法的實現(xiàn)來看,View的寬/高由SpecSize決定,所有我們可以得出如下結(jié)論:直接繼承View的自定義控件需要重寫onMeasure方法并設(shè)置wrap_content時的自身大小,否則在布局中使用wrap_content就相當(dāng)于使用match_parent。
代碼如下:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
    if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasureDimension(mWidth, mHeight);
    } elss if(widthSpecMode == MeasureSpec.AT_MOST) {
        setMeasureDimension(mWidth, heightSpecSize );
    } elss if(heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasureDimension(widthSpecSize , mHeight);
    }
}

mWidth、mHeight是給View指定的默認(rèn)的內(nèi)部寬/高,并在wrap_content時設(shè)置此寬/高。對于非wrap_content情形,沿用系統(tǒng)的測量值。
這個默認(rèn)的內(nèi)部寬/高可以根據(jù)需要靈活指定,例如TextView、ImageView等控件針對wrap_content情形在onMeasure方法均做了特殊處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容