關於View測量中的onMeasure函式
在自定義View中我們通常會重寫onMeasure,下面來說說這個onMeasure有什麼作用
onMeasure主要用於對於View繪製時進行測量
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
setMeasuredDimension是設定它的寬度和高度
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; }
上面用來獲取寬高的函式,可以看出這裡有3種模式:
UNSPECIFIED
這種模式它的result就是size, size是通過getSuggestedMinimumWidth()和getSuggestedMinimumHeight()獲取的, 看看getSuggestedMinimumWidth
protected int getSuggestedMinimumWidth() { return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); }
通常mBackground是通過外部setBackgroundDrawable呼叫賦值的. mMinWidth也可以通過外部負責,也可以通過屬性賦值
case R.styleable.View_minWidth: mMinWidth = a.getDimensionPixelSize(attr, 0); break;
public void setMinimumWidth(int minWidth) { mMinWidth = minWidth; requestLayout(); }
通常UNSPECIFIED是不會呼叫到的.所以我們無需過度關心它的情況.
AT_MOST
AT_MOST對於xml屬性中的wrap_content, 就是適用view內容的大小,但是自定義view情況設定wrap_content通常會傳入填滿父控制元件的specSize。這點從這裡可以看出
case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize;
這顯然不是我們希望看到的,所以自定義需要重寫onMeasure,來對應這種情況
EXACTLY
EXACTLY模式對應制定的寬高和match_partent, 用來精確的設定寬高.
接下來說說怎麼重寫onMeasure這個函式,重寫onMeasure主要是為了爭對設定wrap_content,自定義view填充父容器的情況,所以我們只是爭對MeasureSpec.AT_MOST這種情況.
private int measureWidth(int measureSpec){ int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = 200; break; case MeasureSpec.AT_MOST: result = Math.min(result,specSize); break; case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
measureHeight和measureWidth是一樣的,注意Math.min(result,specSize)這段程式碼,用來防止實際父控制元件的大小比指定的200要小,最終呼叫:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); }
最後
在現在這個金三銀四的面試季,我自己在網上也蒐集了很多資料做成了文件和架構視訊資料免費分享給大家【 包括高階UI、效能優化、架構師課程、NDK、Kotlin、混合式開發(ReactNative+Weex)、Flutter等架構技術資料 】,希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。
資料獲取方式:加入Android架構交流QQ群聊:513088520 ,進群即領取資料!!!
點選連結加入群聊【Android移動架構總群】:加入群聊

資料大全