<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #### 4.2.2 MeasureSpec和LayoutParams的對應關系 上面提到,系統內部是通過MeasureSpec來進行View的測量,但是正常情況下我們使用View指定MeasureSpec,盡管如此,但是我們可以給View設置LayoutParams。在View測量的時候,系統會將LayoutParams在父容器的約束下轉換成對應的MeasureSpec,然后再根據這個MeasureSpec來確定View測量后的寬/高。需要注意的是,MeasureSpec不是唯一由LayoutParams決定的,LayoutParams需要和父容器一起才能決定View的MeasureSpec,從而進一步決定View的寬/高。另外,對于頂級View(即DecorView)和普通View來說,MeasureSpec的轉換過程略有不同。對于DecorView,其MeasureSpec由窗口的尺寸和其自身的LayoutParams來共同確定;對于普通View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams來共同決定,MeasureSpec一旦確定后,onMeasure中就可以確定View的測量寬/高。 對于DecorView來說,在ViewRootImpl中的measureHierarchy方法中有如下一段代碼,它展示了DecorView的MeasureSpec的創建過程,其中desiredWindowWidth和desired-WindowHeight是屏幕的尺寸: childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp. height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); 接著再看一下getRootMeasureSpec方法的實現: private static int getRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: // Window can't resize. Force root view to be windowSize. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec. EXACTLY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: // Window can resize. Set max size for root view. measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec. AT_MOST); break; default: // Window wants to be an exact size. Force root view to be that size. measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, Measure- Spec.EXACTLY); break; } return measureSpec; } 通過上述代碼,DecorView的MeasureSpec的產生過程就很明確了,具體來說其遵守如下規則,根據它的LayoutParams中的寬/高的參數來劃分。 * LayoutParams.MATCH_PARENT:精確模式,大小就是窗口的大小; * LayoutParams.WRAP_CONTENT:最大模式,大小不定,但是不能超過窗口的大小; * 固定大小(比如100dp):精確模式,大小為LayoutParams中指定的大小。 對于普通View來說,這里是指我們布局中的View, View的measure過程由ViewGroup傳遞而來,先看一下ViewGroup的measureChildWithMargins方法: protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayout- Params(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidth MeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeight- MeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } 上述方法會對子元素進行measure,在調用子元素的measure方法之前會先通過getChildMeasureSpec方法來得到子元素的MeasureSpec。從代碼來看,很顯然,子元素的MeasureSpec的創建與父容器的MeasureSpec和子元素本身的LayoutParams有關,此外還和View的margin及padding有關,具體情況可以看一下ViewGroup的getChildMeasureSpec方法,如下所示。 public static int getChildMeasureSpec(int spec, int padding, int child- Dimension) { int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } 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; // Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } 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; } 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; // Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = 0; resultMode = 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); } 上述方法不難理解,它的主要作用是根據父容器的MeasureSpec同時結合View本身的LayoutParams來確定子元素的MeasureSpec,參數中的padding是指父容器中已占用的空間大小,因此子元素可用的大小為父容器的尺寸減去padding,具體代碼如下所示。 int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); getChildMeasureSpec清楚展示了普通View的MeasureSpec的創建規則,為了更清晰地理解getChildMeasureSpec的邏輯,這里提供一個表,表中對getChildMeasureSpec的工作原理進行了梳理,請看表4-1。注意,表中的parentSize是指父容器中目前可使用的大小。 :-: 表4-1 普通View的MeasureSpec的創建規則 ![](https://img.kancloud.cn/61/ed/61ed8d409cb1b09f5575c1f51ab7ae79_1351x364.png) 針對表4-1,這里再做一下說明。前面已經提到,對于普通View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams來共同決定,那么針對不同的父容器和View本身不同的LayoutParams, View就可以有多種MeasureSpec。這里簡單說一下,當View采用固定寬/高的時候,不管父容器的MeasureSpec是什么,View的MeasureSpec都是精確模式并且其大小遵循Layoutparams中的大小。當View的寬/高是match_parent時,如果父容器的模式是精準模式,那么View也是精準模式并且其大小是父容器的剩余空間;如果父容器是最大模式,那么View也是最大模式并且其大小不會超過父容器的剩余空間。當View的寬/高是wrap_content時,不管父容器的模式是精準還是最大化,View的模式總是最大化并且大小不能超過父容器的剩余空間。可能讀者會發現,在我們的分析中漏掉了UNSPECIFIED模式,那是因為這個模式主要用于系統內部多次Measure的情形,一般來說,我們不需要關注此模式。 通過表4-1可以看出,只要提供父容器的MeasureSpec和子元素的LayoutParams,就可以快速地確定出子元素的MeasureSpec了,有了MeasureSpec就可以進一步確定出子元素測量后的大小了。需要說明的是,表4-1并非是什么經驗總結,它只是getChildMeasureSpec這個方法以表格的方式呈現出來而已。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看