ViewGroup的onMeasure探讨

如果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的能给他的最大宽度。
]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容