View和ViewGroup的measure

原文地址

在View.java中的定義:

public final void measure(int widthMeasureSpec,int heightMeasureSpec){
    ... 
    onMeasure();
    ...
}

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

public static int getDefaultSize(int size, int measureSpec) {  
    int result = size;  
    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;  
} 

在ViewGroup中:

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {  
     final int size = mChildrenCount;  
     final View[] children = mChildren;  
     for (int i = 0; i < size; ++i) {  
         final View child = children[i];  
         if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {  
             measureChild(child, widthMeasureSpec, heightMeasureSpec);  
         }  
     }  
 }  

protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {  
    final LayoutParams lp = child.getLayoutParams();  
    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width);  
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height);  
    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  
}

protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {  
    final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();  
    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width);  
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height);  
    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  
} 

說明:

  1. measure是final修飾的方法,不可被重寫。
    在外部調(diào)用時,直接調(diào)用view.measure(int wSpec, int hSpec)。
    measure中調(diào)用了onMeasure。
    自定義view時,重寫onMeasure即可。

  2. MeasureSpec 這是一個含mode和size的結(jié)合體,不需要我們來具體的關(guān)心。當(dāng)在測量時,可以調(diào)用MeasureSpec.getSize|getMode 得到相應(yīng)的size和mode。然后使用MeasureSpec.makeMeasureSpec(size,mode); 來創(chuàng)建MeasureSpec對象。那么mode是怎么來的呢?是根據(jù)使用該自定義view時的layoutWith|height參數(shù)決定的,所以不能自己隨便new一個。而size可以自己指定,也可以直接使用 measureSpec.getSize。

  3. 如果是一個View,重寫onMeasure時要注意:如果在使用自定義view時,用了wrap_content。那么在onMeasure中就要調(diào)用setMeasuredDimension,來指定view的寬高。如果使用的fill_parent或者一個具體的dp值。那么直接使用super.onMeasure即可。

  4. 如果是一個ViewGroup,重寫onMeasure時要注意:首先,結(jié)合上面兩條,來測量自身的寬高。然后,需要測量子View的寬高。測量子view的方式有:

    • getChildAt(int index).可以拿到index上的子view。通過getChildCount得到子view的數(shù)目,再循環(huán)遍歷出子view。接著,subView.measure(int wSpec, int hSpec); //使用子view自身的測量方法
    • 或者調(diào)用viewGroup的測量子view的方法:
      //某一個子view,多寬,多高, 內(nèi)部加上了viewGroup的padding值
      measureChild(subView, int wSpec, int hSpec);
      //所有子view 都是 多寬,多高, 內(nèi)部調(diào)用了measureChild方法
      measureChildren(int wSpec, int hSpec);
      //某一個子view,多寬,多高, 內(nèi)部加上了viewGroup的padding值、margin值和傳入的寬高wUsed、hUsed
      measureChildWithMargins(subView, intwSpec, int wUsed, int hSpec, int hUsed);
最后編輯于
?著作權(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)容