美文网首页
自定义View - 15.measure()源码分析

自定义View - 15.measure()源码分析

作者: zsj1225 | 来源:发表于2018-07-01 17:57 被阅读20次
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.zsj.letterfilterlistview.MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="222" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="222" />
    
    </LinearLayout>
    
    

    上面布局是如果测量的.

    从performTraversals开始
    第一个调用的方法:performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    --> mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    -->onMeasure(widthMeasureSpec, heightMeasureSpec); //测量开始
    -->LinearLayout.onMeasure(widthMeasureSpec, heightMeasureSpec);
    -->measureVertical(widthMeasureSpec, heightMeasureSpec);
    -->measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
    heightMeasureSpec, usedHeight);
    -->measureChildWithMargins(child, widthMeasureSpec, totalWidth,
    heightMeasureSpec, totalHeight);
    childWidthMeasureSpec,childHeightMeasureSpec测量模式,把这两个测量模式传给自View,这里就是TextView
    childWidthMeasureSpec是怎么来的.

    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) {
            // 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;
            
    }
    
    public class TextView extends View {
        public TextView(Context context) {
            super(context);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //widthMeasureSpec == childWidthMeasureSpec
            //heightMeasureSpec == childHeightMeasureSpec
    
            //wrap_content 对应 AT_MOST
            //match_parent ,100dp 对应 EXACTLY
    
           //模式和大小是由父布局和自己决定的
          //比如 父布局是包裹内容,就算子布局是match_parent,这时候计算测量模式还是AT_MOST.
    具体规则看.ViewGroup的getChildMeasureSpec方法.
        }
    }
    

    --> child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

    这个时候我们都会调用setMeasuredDimension().这个时候我的布局才真正指定宽度和高度.这时候mMeasuredWidth和mMeasuredHeight才开始有值.

    接着执行ViewGroup的onMeasure() 方法,这时候需要指定自己的宽高.
    childHeight = child.getMeasuredHeight() + share;LinearLayout的高度算法如果是垂直方向是不断叠加子View的高度.

    总结:
    performMeasure():用于指定和测量layout中所有控件的宽高.
    对于ViewGroup,先去测量里面子孩子,根据子孩子的宽高再来计算和指定自己的宽高.
    对于View,它的宽高是由自己和父布局决定的.

    相关文章

      网友评论

          本文标题:自定义View - 15.measure()源码分析

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