美文网首页
ViewGroup的onMeasure探讨

ViewGroup的onMeasure探讨

作者: bethkede | 来源:发表于2020-04-16 17:23 被阅读0次

    如果LinearLayout的宽度是wrap_content,里面TextView 的宽度是match_parent,那么TextView和LinearLayout的宽度测量要怎么测量,

    <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
        </LinearLayout>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="100dp">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
        </RelativeLayout>
    

    widthMeasureSpec 与 heightMeasureSpec是一个int型的变量,高2位用来封装MeasureMode,剩下的封装parent能够容纳的最大值,MeasureSpec.getMode(widthMeasureSpec),MeasureSpec.getSize(widthMeasureSpec)。如果ViewGroup的宽度是EXACTLY(match_parent,100dp)直接使用固定值来测量,就是100dp或者是parent的宽度,如果是wrap_content,就需要测量childView的宽度,测量时包括childView的排列方(LinearLayout,RelativeLayout等)。

    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            final int count = getChildCount();
    
            int maxHeight = 0;
            int maxWidth = 0;
            int measuredChildState = 0;
    
            // Find rightmost and bottom-most child
            for (int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if (child.getVisibility() != GONE) {
                    measureChild(child, widthMeasureSpec, heightMeasureSpec);
                    maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
                    maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
                    measuredChildState = combineMeasuredStates(measuredChildState,
                            child.getMeasuredState());
                }
            }
    
            // Account for padding too
            maxWidth += mPaddingLeft + mPaddingRight;
            maxHeight += mPaddingTop + mPaddingBottom;
    
            // Check against our minimum height and width
            maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
            maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
    
            setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, measuredChildState),
                    resolveSizeAndState(maxHeight, heightMeasureSpec,
                            measuredChildState<<MEASURED_HEIGHT_STATE_SHIFT));
        }
    
     protected void measureChild(View child, int parentWidthMeasureSpec,
                int parentHeightMeasureSpec) {
            final LayoutParams lp = child.getLayoutParams();
    
            final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                    mPaddingLeft + mPaddingRight, lp.width);
            final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                    mPaddingTop + mPaddingBottom, lp.height);
    
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }
    

    计算childView的时候,传递进了parentWidthMeasureSpec,我们继续往下跟。

      public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
            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) {
    
          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;
    
            ...
        }
    

    回到刚才的问题上,LinearLayout的宽度是wrap_content对应AT_MOST,childDimension对应MATCH_PARENT,所以在这里即使设置了TextView的宽度是match_parent,实际上系统帮我们转换成了wrap_content模式,宽度是parent的specSize,parent的宽度实际上是他的parent的能给他的最大宽度。
    ]

    相关文章

      网友评论

          本文标题:ViewGroup的onMeasure探讨

          本文链接:https://www.haomeiwen.com/subject/kkjdvhtx.html