View的measure

昨天爬了一天的山~,我的腳已經(jīng)崩潰了所禀,嘻嘻不過還是挺開心的界斜,今天我們要總結(jié)下View的measure(測量)ViewGroup的measure
我們平常繼承View 和ViewGroup 這2個方法呢,都是會有一個測量的步驟的,如果只是一個View那么measure完了就完了窥翩,如果是ViewGroup不僅自己要測量下业岁,自己的子View也要測量下。
View里面的measure

 public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
        boolean optical = isLayoutModeOptical(this);
       .....省略
        if (forceLayout || needsLayout) {
            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
            resolveRtlPropertiesIfNeeded();
            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                      //我們直接看這里鳍烁,因為這里是設(shè)置布局大小的地方
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            } else {
                long value = mMeasureCache.valueAt(cacheIndex);
                // Casting a long to int drops the high 32 bits, no mask needed
                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }
      .....省略

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
//setMeasuredDimension 方法直接設(shè)置寬高了
    }

getDefaultSize方法主要返回的是一個大小值(寬度和高度)

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;
    //不管你是wrap還是match最后的結(jié)果由specSize決定
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

UNSPECIFIED測量模式我們先不理它叨襟,其它2種的測量模式最后的結(jié)果都是specSize,就是View測量后的大小
我們這里面還有一個getSuggestedMinimumWidth()和getSuggestedMinimumHeight()2個方法幔荒,我們看其中一個

 protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }
//如果backgroud(背景)==null,我們就取mMinWidth糊闽,否則我們就去后面2個比較的那個最大值
//這里的mMinWidth==android:minWidth,當然如果我們沒有去指定的話爹梁,mMinWidth=0了

我們點擊mBackground.getMinimumWidth()這個方法看

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

現(xiàn)在我們知道了一個View不管你設(shè)置wrap還是match右犹,最后的結(jié)果都是由
specSize 它決定,現(xiàn)在有一個問題來了姚垃,當我們自定義View的時候念链,我們平常寫寬度/高度為wrap,我們會在腦海中想象他是個包裹的狀態(tài)积糯,但是當我們真正去實驗的時候掂墓,發(fā)現(xiàn)他卻是全屏的狀態(tài)(match),這個就讓我們很詫異看成,很疑惑?君编。
現(xiàn)在我們目前只知道2點
1、我們不管是wrap還是match最后的結(jié)果都是由specSize決定你的大小(代碼可以看出來)
2川慌、Linlayout在繪制布局的時候會調(diào)用measureChildWithMargins方法吃嘿,在這個方法里面會調(diào)用child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
當然第二點我們后面再講到
如果你看過我對MeasureSpece的總結(jié)的話你應(yīng)該就知道了

3.png

我們可以明白這一點,Linlayout(父布局)決定了子布局的大小梦重,本文中specSize的大小由父容器來給你決定兑燥,他決定你你有多大的使用空間(父容器剩余的空間),我們可以通過上面的圖片知道琴拧,如果我們的 childLayoutParams的參數(shù)是wrap_content那么我們不管父容器是wrap還是match,子容器的測量模式都是AT_MOST降瞳,但是它的寬高大小都是parentSize的大小,也就是父容器的大邪丁(你要明白這一點力崇,你需要看我前面的學習總結(jié))
下面這個例子很好的展示了當子容器是wrap的時候,沾滿全屏的情況
1.png

現(xiàn)在大家看到的這個效果是一個Linlayout赢织,嵌套一個自定義的view

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <scanning.mobile.com.viewstudy.viewStu.st
        android:background="@color/colorAccent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

但是我嵌套里面的寬/高都是wrap_content,但是我們卻看到的是沾滿全屏了
這個是為啥亮靴?我們可以采用剛剛我們學到的知識來解釋,
我們拿著我們剛剛參考那張表格來看
首先父容器是match_parent于置,那么對應(yīng)的測量模式是:EXACTLY(精確模式)茧吊,子容器是wrap_content贞岭,那么它對應(yīng)的模式就是AT_MOST

        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);//父容器的大小
        int size = Math.max(0, specSize - padding);//獲取剩下的空間
else if (childDimension == LayoutParams.WRAP_CONTENT) {
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }

我們知道我們最后的size就是Math.max(0, specSize - padding);//獲取剩下的空間,
所以我們就是父容器的大小了搓侄,那么問題了來了瞄桨,我們要如何來解決這樣的問題?

public class st extends View{
    private static final String TAG = st.class.getSimpleName();
    public st(Context context) {
        super(context);
    }

    public st(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public st(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    int height=200;
    int width = 200;
    @Override
    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){//他會進入這里讶踪,所以我們在這里直接來解決
            setMeasuredDimension(width,height);
        }else if (widthSpecMode==MeasureSpec.AT_MOST){
            setMeasuredDimension(width,heightSpecSize);
        }else if (heightSpecMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(height,widthSpecSize);
        }
    }
}

獲取它的測量模式芯侥,根據(jù)測量模式來修改


`{~3GBS2$20GCFYV$0W)%FO.png

學習資源書籍:《Android 開發(fā)藝術(shù)探索》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乳讥,隨后出現(xiàn)的幾起案子柱查,更是在濱河造成了極大的恐慌,老刑警劉巖云石,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唉工,死亡現(xiàn)場離奇詭異,居然都是意外死亡汹忠,警方通過查閱死者的電腦和手機淋硝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宽菜,“玉大人谣膳,你說我怎么就攤上這事∏ο纾” “怎么了参歹?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長隆判。 經(jīng)常有香客問我,道長僧界,這世上最難降的妖魔是什么侨嘀? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮捂襟,結(jié)果婚禮上咬腕,老公的妹妹穿的比我還像新娘。我一直安慰自己葬荷,他們只是感情好涨共,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宠漩,像睡著了一般举反。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上扒吁,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天火鼻,我揣著相機與錄音,去河邊找鬼。 笑死魁索,一個胖子當著我的面吹牛融撞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播粗蔚,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼尝偎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鹏控?” 一聲冷哼從身側(cè)響起致扯,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牧挣,沒想到半個月后急前,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瀑构,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年裆针,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺晌。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡世吨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呻征,到底是詐尸還是另有隱情耘婚,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布陆赋,位于F島的核電站沐祷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏攒岛。R本人自食惡果不足惜赖临,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灾锯。 院中可真熱鬧兢榨,春花似錦、人聲如沸顺饮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兼雄。三九已至吟逝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間君旦,已是汗流浹背澎办。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工嘲碱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人局蚀。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓麦锯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親琅绅。 傳聞我的和親對象是個殘疾皇子扶欣,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容