国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android MeasureSpec的理解和源碼的解析

2019-10-22 18:28:31
字體:
供稿:網(wǎng)友

Android  MeasureSpec的理解和源碼的解析

MeasureSpec的創(chuàng)建規(guī)則:

Android,MeasureSpec,MeasureSpec實(shí)例詳解

實(shí)例詳解:

package cc.ww;  import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.widget.LinearLayout;  /**  * @author http://blog.csdn.net/lfdfhl  *  * 文檔描述:  * 關(guān)于MeasureSpec的理解  *  * (1) MeasureSpec基礎(chǔ)知識  *   MeasureSpec通常翻譯為"測量規(guī)格",它是一個(gè)32位的int數(shù)據(jù).  *   其中高2位代表SpecMode即某種測量模式,低32位為SpecSize代表在該模式下的規(guī)格大小.  *   可以通過:   *   int specMode = MeasureSpec.getMode(measureSpec) 獲取specMode     int specSize = MeasureSpec.getSize(measureSpec) 獲取SpecSize           常用的SpecMode有三種:           MeasureSpec.EXACTLY       官方文檔     Measure specification mode: The parent has determined an exact size     for the child. The child is going to be given those bounds regardless of how big it wants to be.          父容器已經(jīng)檢測出子View所需要的精確大小.該子View最終的測量大小即為SpecSize.     (1) 當(dāng)子View的LayoutParams的寬(高)采用具體的值(如100px)時(shí)且父容器的MeasureSpec為 MeasureSpec.EXACTLY或者     MeasureSpec.AT_MOST或者M(jìn)easureSpec.UNSPECIFIED時(shí):          系統(tǒng)返回給該子View的specMode就為 MeasureSpec.EXACTLY          系統(tǒng)返回給該子View的specSize就為子View自己指定的大小(childSize)          通俗地理解:          子View的LayoutParams的寬(高)采用具體的值(如100px)時(shí),那么說明該子View的大小是非常明確的,明確到已經(jīng)用具體px值          指定的地步了.那么此時(shí)不管父容器的specMode是什么,系統(tǒng)返回給該子View的specMode總是MeasureSpec.EXACTLY,并且          系統(tǒng)返回給該子View的specSize就為子View自己指定的大小(childSize).         (2) 當(dāng)子View的LayoutParams的寬(高)采用match_parent時(shí)并且父容器的MeasureSpec為 MeasureSpec.EXACTLY時(shí):          系統(tǒng)返回給該子View的specMode就為 MeasureSpec.EXACTLY          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)          通俗地理解:       子View的LayoutParams的寬(高)采用match_parent時(shí)并且父容器的MeasureSpec為 MeasureSpec.EXACTLY.       這時(shí)候說明子View的大小還是挺明確的:就是要和父容器一樣大,更加直白地說就是父容器要怎樣子View就要怎樣.       所以,如果父容器MeasureSpec為 MeasureSpec.EXACTLY那么:       系統(tǒng)返回給該子View的specMode就為 MeasureSpec.EXACTLY,和父容器一樣.          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize),就是父容器的剩余大小.          同樣的道理如果此時(shí),MeasureSpec為 MeasureSpec.AT_MOST呢?          系統(tǒng)返回給該子View的specMode也為 MeasureSpec.AT_MOST,和父容器一樣.          系統(tǒng)返回給該子View的specSize也為該父容器剩余空間的大小(parentLeftSize),就是父容器的剩余大小.           MeasureSpec.AT_MOST       官方文檔     The child can be as large as it wants up to the specified size.       父容器指定了一個(gè)可用大小即specSize,子View的大小不能超過該值.     (1) 當(dāng)子View的LayoutParams的寬(高)采用match_parent時(shí)并且父容器的MeasureSpec為 MeasureSpec.AT_MOST時(shí):          系統(tǒng)返回給該子View的specMode就為 MeasureSpec.AT_MOST          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)          這種情況已經(jīng)在上面介紹 MeasureSpec.EXACTLY時(shí)已經(jīng)討論過了.    (2) 當(dāng)子View的LayoutParams的寬(高)采用wrap_content時(shí)并且父容器的MeasureSpec為 MeasureSpec.EXACTLY時(shí):          系統(tǒng)返回給該子View的specMode就為 MeasureSpec.AT_MOST          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)          通俗地理解:          子View的LayoutParams的寬(高)采用wrap_content時(shí)說明這個(gè)子View的寬高不明確,要視content而定.          這個(gè)時(shí)候如果父容器的MeasureSpec為 MeasureSpec.EXACTLY即父容器是一個(gè)精確模式;這個(gè)時(shí)候簡單地說          子View是不確定的,父容器是確定的,那么          系統(tǒng)返回給該子View的specMode也就是不確定的即為 MeasureSpec.AT_MOST          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)     (3) 當(dāng)子View的LayoutParams的寬(高)采用wrap_content時(shí)并且父容器的MeasureSpec為 MeasureSpec.AT_MOST時(shí):          系統(tǒng)返回給該子View的specMode就為 MeasureSpec.AT_MOST          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)          通俗地理解:          子View的LayoutParams的寬(高)采用wrap_content時(shí)說明這個(gè)子View的寬高不明確,要視content而定.          這個(gè)時(shí)候如果父容器的MeasureSpec為 MeasureSpec.AT_MOST這個(gè)時(shí)候簡單地說          子View是不確定的,父容器也是不確定的,那么          系統(tǒng)返回給該子View的specMode也就是不確定的即為 MeasureSpec.AT_MOST          系統(tǒng)返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize)                  MeasureSpec.UNSPECIFIED       官方文檔     The parent has not imposed any constraint on the child. It can be whatever size it wants.       父容器不對子View的大小做限制.       一般用作Android系統(tǒng)內(nèi)部,或者ListView和ScrollView.在此不做討論.             關(guān)于這個(gè)三種測量規(guī)格下面的源碼分析中體現(xiàn)得很明顯,也可參考以下附圖.      * (2) 在onMeasure()時(shí)子View的MeasureSpec的形成過程分析  *   關(guān)于該技術(shù)點(diǎn)的討論,請看下面的源碼分析.  *  */ public class UnderstandMeasureSpec {      /**    * 第一步:    * 在ViewGroup測量子View時(shí)會調(diào)用到measureChildWithMargins()方法,或者與之類似的方法.    * 請注意方法的參數(shù):    * @param child    * 子View    * @param parentWidthMeasureSpec    * 父容器(比如LinearLayout)的寬的MeasureSpec    * @param widthUsed    * 父容器(比如LinearLayout)在水平方向已經(jīng)占用的空間大小    * @param parentHeightMeasureSpec    * 父容器(比如LinearLayout)的高的MeasureSpec    * @param heightUsed    * 父容器(比如LinearLayout)在垂直方向已經(jīng)占用的空間大小    *    * 在該方法中主要有四步操作,其中很重要的是調(diào)用了getChildMeasureSpec()方法來確定    * 子View的MeasureSpec.詳情參見代碼分析    */   protected void measureChildWithMargins(View child,int parentWidthMeasureSpec, int widthUsed,                            int parentHeightMeasureSpec, int heightUsed) {     //1 得到子View的LayoutParams     final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();     //2 得到子View的寬的MeasureSpec     final int childWidthMeasureSpec = getChildMeasureSpec     (parentWidthMeasureSpec,mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width);     //3 得到子View的高的MeasureSpec     final int childHeightMeasureSpec = getChildMeasureSpec     (parentHeightMeasureSpec,mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height);     //4 測量子View     child.measure(childWidthMeasureSpec, childHeightMeasureSpec);   }         /**    * getChildMeasureSpec()方法確定子View的MeasureSpec    * 請注意方法的參數(shù):    * @param spec    * 父容器(比如LinearLayout)的寬或高的MeasureSpec    * @param padding    * 父容器(比如LinearLayout)在垂直方向或者水平方向已被占用的空間.    * 在measureChildWithMargins()方法里調(diào)用getChildMeasureSpec()時(shí)注意第二個(gè)參數(shù)的構(gòu)成:    * 比如:mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin    * 其中:    * mPaddingLeft和mPaddingRight表示父容器左右兩內(nèi)側(cè)的padding    * lp.leftMargin和lp.rightMargin表示子View左右兩外側(cè)的margin    * 這四部分都不可以再利用起來布局子View.所以說這些值的和表示:    * 父容器在水平方向已經(jīng)被占用的空間    * 同理:    * mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin    * 表示:    * 父容器(比如LinearLayout)在垂直方向已被占用的空間.    * @param childDimension    * 通過子View的LayoutParams獲取到的子View的寬或高    *    *    * 經(jīng)過以上分析可從getChildMeasureSpec()方法的第一個(gè)參數(shù)和第二個(gè)參數(shù)可以得出一個(gè)結(jié)論:    * 父容器(如LinearLayout)的MeasureSpec和子View的LayoutParams共同決定了子View的MeasureSpec!!!    *    *    *    */    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {       /**        * 第一步:得到父容器的specMode和specSize        */       int specMode = MeasureSpec.getMode(spec);       int specSize = MeasureSpec.getSize(spec);       /**        * 第二步:得到父容器在水平方向或垂直方向可用的最大空間值.        *    關(guān)于padding參見上面的分析        */       int size = Math.max(0, specSize - padding);        int resultSize = 0;       int resultMode = 0;               /**        * 第三步:確定子View的specMode和specSize.        *    在此分為三種情況進(jìn)行.        */       switch (specMode) {       /**        * 第一種情況:        * 父容器的測量模式為EXACTLY        *        * 請注意兩個(gè)系統(tǒng)常量:        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此處的代碼:        * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.EXACTLY:         /**          * 當(dāng)父容器的測量模式為EXACTLY時(shí)如果:          * 子View的寬或高是一個(gè)精確的值,比如100px;          * 那么:          * 子View的size就是childDimension          * 子View的mode也為MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 當(dāng)父容器的測量模式為EXACTLY時(shí)如果:          * 子View的寬或高是LayoutParams.MATCH_PARENT          * 那么:          * 子View的size就是父容器在水平方向或垂直方向可用的最大空間值即size          * 子View的mode也為MeasureSpec.EXACTLY          */         } else if (childDimension == LayoutParams.MATCH_PARENT) {           // Child wants to be our size. So be it.           resultSize = size;           resultMode = MeasureSpec.EXACTLY;         /**          * 當(dāng)父容器的測量模式為EXACTLY時(shí)如果:          * 子View的寬或高是LayoutParams.WRAP_CONTENT          * 那么:          * 子View的size就是父容器在水平方向或垂直方向可用的最大空間值即size          * 子View的mode為MeasureSpec.AT_MOST          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size. It can't be bigger than us.           resultSize = size;           resultMode = MeasureSpec.AT_MOST;         }         break;        /**        * 第二種情況:        * 父容器的測量模式為AT_MOST        *        * 請注意兩個(gè)系統(tǒng)常量:pp        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此處的代碼:        * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.AT_MOST:         /**          * 當(dāng)父容器的測量模式為AT_MOST時(shí)如果:          * 子View的寬或高是一個(gè)精確的值,比如100px;          * 那么:          * 子View的size就是childDimension          * 子View的mode也為MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           // Child wants a specific size... so be it           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 當(dāng)父容器的測量模式為AT_MOST時(shí)如果:          * 子View的寬或高為LayoutParams.MATCH_PARENT          * 那么:          * 子View的size就是父容器在水平方向或垂直方向可用的最大空間值即size          * 子View的mode也為MeasureSpec.AT_MOST          */         } else if (childDimension == LayoutParams.MATCH_PARENT) {           // Child wants to be our size, but our size is not fixed.           // Constrain child to not be bigger than us.           resultSize = size;           resultMode = MeasureSpec.AT_MOST;          /**          * 當(dāng)父容器的測量模式為AT_MOST時(shí)如果:          * 子View的寬或高為LayoutParams.WRAP_CONTENT          * 那么:          * 子View的size就是父容器在水平方向或垂直方向可用的最大空間值即size          * 子View的mode也為MeasureSpec.AT_MOST          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size. It can't be           // bigger than us.           resultSize = size;           resultMode = MeasureSpec.AT_MOST;         }         break;        /**        * 第三種情況:        * 父容器的測量模式為UNSPECIFIED        *        * 請注意兩個(gè)系統(tǒng)常量:        * LayoutParams.MATCH_PARENT=-1        * LayoutParams.WRAP_CONTENT=-2        * 所以在此處的代碼:        * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT        */       case MeasureSpec.UNSPECIFIED:         /**          * 當(dāng)父容器的測量模式為UNSPECIFIED時(shí)如果:          * 子View的寬或高是一個(gè)精確的值,比如100px;          * 那么:          * 子View的size就是childDimension          * 子View的mode也為MeasureSpec.EXACTLY          */         if (childDimension >= 0) {           // Child wants a specific size... let him have it           resultSize = childDimension;           resultMode = MeasureSpec.EXACTLY;         /**          * 當(dāng)父容器的測量模式為UNSPECIFIED時(shí)如果:          * 子View的寬或高為LayoutParams.MATCH_PARENT          * 那么:          * 子View的size為0          * 子View的mode也為MeasureSpec.UNSPECIFIED          */         } else if (childDimension == LayoutParams.MATCH_PARENT) {           // Child wants to be our size... find out how big it should be           resultSize = 0;           resultMode = MeasureSpec.UNSPECIFIED;         /**          * 當(dāng)父容器的測量模式為UNSPECIFIED時(shí)如果:          * 子View的寬或高為LayoutParams.WRAP_CONTENT          * 那么:          * 子View的size為0          * 子View的mode也為MeasureSpec.UNSPECIFIED          */         } else if (childDimension == LayoutParams.WRAP_CONTENT) {           // Child wants to determine its own size.... find out how big it should be           resultSize = 0;           resultMode = MeasureSpec.UNSPECIFIED;         }         break;       }       return MeasureSpec.makeMeasureSpec(resultSize, resultMode);     }        } 

 如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 吉林市| 上蔡县| 桃源县| 邹城市| 临西县| 巴楚县| 呈贡县| 衡水市| 德钦县| 彩票| 洪江市| 绥滨县| 广汉市| 文成县| 将乐县| 桂林市| 哈密市| 桦川县| 安庆市| 叶城县| 北海市| 惠安县| 衡水市| 德阳市| 霍林郭勒市| 微山县| 天水市| 靖西县| 读书| 澄江县| 卓资县| 随州市| 连平县| 颍上县| 荃湾区| 平江县| 定边县| 萨迦县| 莱芜市| 论坛| 上栗县|