中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中MeasureSpec的作用是什么

發布時間:2021-06-26 17:19:50 來源:億速云 閱讀:181 作者:Leah 欄目:移動開發

Android中MeasureSpec的作用是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

MeasureSpec的創建規則:

Android中MeasureSpec的作用是什么

實例詳解:

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 
 * 
 * 文檔描述: 
 * 關于MeasureSpec的理解 
 * 
 * (1) MeasureSpec基礎知識 
 *   MeasureSpec通常翻譯為"測量規格",它是一個32位的int數據. 
 *   其中高2位代表SpecMode即某種測量模式,低32位為SpecSize代表在該模式下的規格大小. 
 *   可以通過:  
 *   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. 
         父容器已經檢測出子View所需要的精確大小.該子View最終的測量大小即為SpecSize. 
    (1) 當子View的LayoutParams的寬(高)采用具體的值(如100px)時且父容器的MeasureSpec為 MeasureSpec.EXACTLY或者 
    MeasureSpec.AT_MOST或者MeasureSpec.UNSPECIFIED時: 
         系統返回給該子View的specMode就為 MeasureSpec.EXACTLY 
         系統返回給該子View的specSize就為子View自己指定的大小(childSize) 
         通俗地理解: 
         子View的LayoutParams的寬(高)采用具體的值(如100px)時,那么說明該子View的大小是非常明確的,明確到已經用具體px值 
         指定的地步了.那么此時不管父容器的specMode是什么,系統返回給該子View的specMode總是MeasureSpec.EXACTLY,并且 
         系統返回給該子View的specSize就為子View自己指定的大小(childSize). 
    
    (2) 當子View的LayoutParams的寬(高)采用match_parent時并且父容器的MeasureSpec為 MeasureSpec.EXACTLY時: 
         系統返回給該子View的specMode就為 MeasureSpec.EXACTLY 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
         通俗地理解: 
      子View的LayoutParams的寬(高)采用match_parent時并且父容器的MeasureSpec為 MeasureSpec.EXACTLY. 
      這時候說明子View的大小還是挺明確的:就是要和父容器一樣大,更加直白地說就是父容器要怎樣子View就要怎樣. 
      所以,如果父容器MeasureSpec為 MeasureSpec.EXACTLY那么: 
      系統返回給該子View的specMode就為 MeasureSpec.EXACTLY,和父容器一樣. 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize),就是父容器的剩余大小. 
         同樣的道理如果此時,MeasureSpec為 MeasureSpec.AT_MOST呢? 
         系統返回給該子View的specMode也為 MeasureSpec.AT_MOST,和父容器一樣. 
         系統返回給該子View的specSize也為該父容器剩余空間的大小(parentLeftSize),就是父容器的剩余大小. 
      
    MeasureSpec.AT_MOST 
      官方文檔 
    The child can be as large as it wants up to the specified size. 
      父容器指定了一個可用大小即specSize,子View的大小不能超過該值. 
    (1) 當子View的LayoutParams的寬(高)采用match_parent時并且父容器的MeasureSpec為 MeasureSpec.AT_MOST時: 
         系統返回給該子View的specMode就為 MeasureSpec.AT_MOST 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
         這種情況已經在上面介紹 MeasureSpec.EXACTLY時已經討論過了. 
   (2) 當子View的LayoutParams的寬(高)采用wrap_content時并且父容器的MeasureSpec為 MeasureSpec.EXACTLY時: 
         系統返回給該子View的specMode就為 MeasureSpec.AT_MOST 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
         通俗地理解: 
         子View的LayoutParams的寬(高)采用wrap_content時說明這個子View的寬高不明確,要視content而定. 
         這個時候如果父容器的MeasureSpec為 MeasureSpec.EXACTLY即父容器是一個精確模式;這個時候簡單地說 
         子View是不確定的,父容器是確定的,那么 
         系統返回給該子View的specMode也就是不確定的即為 MeasureSpec.AT_MOST 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
    (3) 當子View的LayoutParams的寬(高)采用wrap_content時并且父容器的MeasureSpec為 MeasureSpec.AT_MOST時: 
         系統返回給該子View的specMode就為 MeasureSpec.AT_MOST 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
         通俗地理解: 
         子View的LayoutParams的寬(高)采用wrap_content時說明這個子View的寬高不明確,要視content而定. 
         這個時候如果父容器的MeasureSpec為 MeasureSpec.AT_MOST這個時候簡單地說 
         子View是不確定的,父容器也是不確定的,那么 
         系統返回給該子View的specMode也就是不確定的即為 MeasureSpec.AT_MOST 
         系統返回給該子View的specSize就為該父容器剩余空間的大小(parentLeftSize) 
         
    
    MeasureSpec.UNSPECIFIED 
      官方文檔 
    The parent has not imposed any constraint on the child. It can be whatever size it wants. 
      父容器不對子View的大小做限制. 
      一般用作Android系統內部,或者ListView和ScrollView.在此不做討論. 
      
      關于這個三種測量規格下面的源碼分析中體現得很明顯,也可參考以下附圖. 
    
 * (2) 在onMeasure()時子View的MeasureSpec的形成過程分析 
 *   關于該技術點的討論,請看下面的源碼分析. 
 * 
 */ 
public class UnderstandMeasureSpec { 
   
  /** 
   * 第一步: 
   * 在ViewGroup測量子View時會調用到measureChildWithMargins()方法,或者與之類似的方法. 
   * 請注意方法的參數: 
   * @param child 
   * 子View 
   * @param parentWidthMeasureSpec 
   * 父容器(比如LinearLayout)的寬的MeasureSpec 
   * @param widthUsed 
   * 父容器(比如LinearLayout)在水平方向已經占用的空間大小 
   * @param parentHeightMeasureSpec 
   * 父容器(比如LinearLayout)的高的MeasureSpec 
   * @param heightUsed 
   * 父容器(比如LinearLayout)在垂直方向已經占用的空間大小 
   * 
   * 在該方法中主要有四步操作,其中很重要的是調用了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 
   * 請注意方法的參數: 
   * @param spec 
   * 父容器(比如LinearLayout)的寬或高的MeasureSpec 
   * @param padding 
   * 父容器(比如LinearLayout)在垂直方向或者水平方向已被占用的空間. 
   * 在measureChildWithMargins()方法里調用getChildMeasureSpec()時注意第二個參數的構成: 
   * 比如:mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin 
   * 其中: 
   * mPaddingLeft和mPaddingRight表示父容器左右兩內側的padding 
   * lp.leftMargin和lp.rightMargin表示子View左右兩外側的margin 
   * 這四部分都不可以再利用起來布局子View.所以說這些值的和表示: 
   * 父容器在水平方向已經被占用的空間 
   * 同理: 
   * mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin 
   * 表示: 
   * 父容器(比如LinearLayout)在垂直方向已被占用的空間. 
   * @param childDimension 
   * 通過子View的LayoutParams獲取到的子View的寬或高 
   * 
   * 
   * 經過以上分析可從getChildMeasureSpec()方法的第一個參數和第二個參數可以得出一個結論: 
   * 父容器(如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); 
      /** 
       * 第二步:得到父容器在水平方向或垂直方向可用的最大空間值. 
       *    關于padding參見上面的分析 
       */ 
      int size = Math.max(0, specSize - padding); 
 
      int resultSize = 0; 
      int resultMode = 0; 
 
       
      /** 
       * 第三步:確定子View的specMode和specSize. 
       *    在此分為三種情況進行. 
       */ 
      switch (specMode) { 
      /** 
       * 第一種情況: 
       * 父容器的測量模式為EXACTLY 
       * 
       * 請注意兩個系統常量: 
       * LayoutParams.MATCH_PARENT=-1 
       * LayoutParams.WRAP_CONTENT=-2 
       * 所以在此處的代碼: 
       * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT 
       */ 
      case MeasureSpec.EXACTLY: 
        /** 
         * 當父容器的測量模式為EXACTLY時如果: 
         * 子View的寬或高是一個精確的值,比如100px; 
         * 那么: 
         * 子View的size就是childDimension 
         * 子View的mode也為MeasureSpec.EXACTLY 
         */ 
        if (childDimension >= 0) { 
          resultSize = childDimension; 
          resultMode = MeasureSpec.EXACTLY; 
        /** 
         * 當父容器的測量模式為EXACTLY時如果: 
         * 子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; 
        /** 
         * 當父容器的測量模式為EXACTLY時如果: 
         * 子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 
       * 
       * 請注意兩個系統常量:pp 
       * LayoutParams.MATCH_PARENT=-1 
       * LayoutParams.WRAP_CONTENT=-2 
       * 所以在此處的代碼: 
       * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT 
       */ 
      case MeasureSpec.AT_MOST: 
        /** 
         * 當父容器的測量模式為AT_MOST時如果: 
         * 子View的寬或高是一個精確的值,比如100px; 
         * 那么: 
         * 子View的size就是childDimension 
         * 子View的mode也為MeasureSpec.EXACTLY 
         */ 
        if (childDimension >= 0) { 
          // Child wants a specific size... so be it 
          resultSize = childDimension; 
          resultMode = MeasureSpec.EXACTLY; 
        /** 
         * 當父容器的測量模式為AT_MOST時如果: 
         * 子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; 
         /** 
         * 當父容器的測量模式為AT_MOST時如果: 
         * 子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 
       * 
       * 請注意兩個系統常量: 
       * LayoutParams.MATCH_PARENT=-1 
       * LayoutParams.WRAP_CONTENT=-2 
       * 所以在此處的代碼: 
       * childDimension >= 0 表示子View的寬或高不是MATCH_PARENT和WRAP_CONTENT 
       */ 
      case MeasureSpec.UNSPECIFIED: 
        /** 
         * 當父容器的測量模式為UNSPECIFIED時如果: 
         * 子View的寬或高是一個精確的值,比如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; 
        /** 
         * 當父容器的測量模式為UNSPECIFIED時如果: 
         * 子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; 
        /** 
         * 當父容器的測量模式為UNSPECIFIED時如果: 
         * 子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); 
    } 
   
   
 
}

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

大名县| 荣昌县| 甘德县| 彰化县| 宝丰县| 石家庄市| 尼勒克县| 营山县| 西乌珠穆沁旗| 古交市| 云阳县| 濉溪县| 绥江县| 临海市| 宾阳县| 临泽县| 车险| 德化县| 桃源县| 石泉县| 霍林郭勒市| 阿合奇县| 青冈县| 新郑市| 孟州市| 西平县| 诸城市| 大新县| 望江县| 定兴县| 六盘水市| 宁远县| 东明县| 长乐市| 沧州市| 西安市| 江山市| 琼中| 蒙城县| 通化市| 海南省|