编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 1.1App启动流程梳理
  • 1.2ActivityThread分析
  • 1.3Context设计思想
  • 2.1Activity基础介绍
  • 2.2Activity启动流程
  • 2.3Activity布局创建
  • 2.4Activity布局绘制
  • 2.5Service基础介绍
  • 2.6Service启动流程
  • 2.7Receiver广播基础
  • 2.8Receiver深入原理
  • 2.9ContentProvider分析
  • 2.10Fragment实践
  • 2.11Intent深入思考
  • 3.1Paint和Canvas
  • 3.2View的绘制基础
  • 3.3onMeasure流程设计
  • 3.4onLayout流程设计
  • 3.5onDraw流程设计
  • 3.6View工作原理
  • 3.7View刷新设计流程
  • 3.8自定义View控件
  • 3.9自定义ViewGroup控件
  • 4.1Handler基础使用
  • 4.2消息机制流程分析
  • 4.3Handler深度解析
  • 4.4Message深度理解
  • 4.5MessageQueue解析
  • 4.6Looper深度解析
  • 4.7理解Handler同步屏障
  • 4.8ThreadLocal分析
  • 4.9ThreadLocal场景
  • 5.1View事件设计思考
  • 5.2View滑动冲突处理
  • 5.3View事件源码分析
  • 5.4View事件总结案例
  • 6.1DecorView设计思想
  • 6.2视图的载体View
  • 6.3视图管理者Window
  • 6.4窗口管理服务WMS
  • 6.5布局解析者Inflater
  • 7.1AsyncTask深入介绍
  • 7.2HandlerThread设计
  • 7.3IntentService设计
  • 8.1IPC通信方式介绍
  • 8.2AIDL进程间通信
  • 8.7Binder通信机制设计
  • /zh/android/basic/9.1注解设计思想和原理.html
  • 9.2APT技术设计详解
  • 9.3APT多种案例实践

3.3onMeasure流程设计

目录介绍

  • 01.Measure流程分析
  • 02.MeasureSpec的确定
  • 03.View的测量流程
  • 04.View的onMeasure源码
  • 05.NestedScrollView测量过程
  • 06.看几个思考题分析
  • 07.View中onMeasure方法
  • 08.ViewGroup中onMeasure方法

01.Measure流程分析

  • 顾名思义,就是测量每个控件的大小。调用measure()方法,进行一些逻辑处理,然后调用onMeasure()方法,在其中调用setMeasuredDimension()设定View的宽高信息,完成View的测量操作。
    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    }
  • measure()方法中,传入了两个参数 widthMeasureSpec, heightMeasureSpec 表示View的宽高的一些信息。
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
  • 由上述流程来看Measure流程很简单,关键点是在于widthMeasureSpec, heightMeasureSpec这两个参数信息怎么获得?
    • 如果有了widthMeasureSpec, heightMeasureSpec,通过一定的处理(可以重写,自定义处理步骤),从中获取View的宽/高,调用setMeasuredDimension()方法,指定View的宽高,完成测量工作。
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //从中获取View的宽/高
        int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        //指定View的宽高,完成测量工作
        setMeasuredDimension(width,height);
    }

02.MeasureSpec的确定

2.1 MeasureSpec是什么

  • 先介绍下什么是MeasureSpec?
    • img
      img
  • MeasureSpec由两部分组成,一部分是测量模式,另一部分是测量的尺寸大小。
    • 其中,Mode模式共分为三类
      • UNSPECIFIED :不对View进行任何限制,要多大给多大,一般用于系统内部
      • EXACTLY:对应LayoutParams中的match_parent和具体数值这两种模式。检测到View所需要的精确大小,这时候View的最终大小就是SpecSize所指定的值
      • AT_MOST :对应LayoutParams中的wrap_content。View的大小不能大于父容器的大小。
  • 那么MeasureSpec又是如何确定的?
    • 对于DecorView,其确定是通过屏幕的大小,和自身的布局参数LayoutParams。
    • 这部分很简单,根据LayoutParams的布局格式(match_parent,wrap_content或指定大小),将自身大小,和屏幕大小相比,设置一个不超过屏幕大小的宽高,以及对应模式。
    • 对于其他View(包括ViewGroup),其确定是通过父布局的MeasureSpec和自身的布局参数LayoutParams。
  • 这部分比较复杂。以下列图表表示不同的情况:
    • img
      img
    • 当子View的LayoutParams的布局格式是wrap_content,可以看到子View的大小是父View的剩余尺寸,和设置成match_parent时,子View的大小没有区别。为了显示区别,一般在自定义View时,需要重写onMeasure方法,处理wrap_content时的情况,进行特别指定。
    • 从这里看出MeasureSpec的指定也是从顶层布局开始一层层往下去,父布局影响子布局。

2.2 MeasureSpec静态类

  • 代码如下所示
    • MeasureSpec总结起来就是:
    • 它由2部分数据组成,分别为定义了View测量的模式和View的测量尺寸大小
    • 其中EXACTLY精确模式表示的是match_parent和具体值;AT_MOST最大模式表示的是wrap_content的情况
    //view.class
    public static class MeasureSpec {
        private static final int MODE_SHIFT = 30;
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
    
        /**
         * 这种模式不用关心
         */
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;
    
        /**
         * 精确模式,对应的是match_parent和具体值,比如100dp
        public static final int EXACTLY     = 1 << MODE_SHIFT;
    
        /**
         * 最大模式,对应的就是wrap_content
         */
        public static final int AT_MOST     = 2 << MODE_SHIFT;
    
       
        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode & MODE_MASK);
            }
        }
    
        /**
         * 获取测量的模式
         */
        @MeasureSpecMode
        public static int getMode(int measureSpec) {
            //noinspection ResourceType
            return (measureSpec & MODE_MASK);
        }
    
        /**
         * 获取测量到的尺寸大小
         */
        public static int getSize(int measureSpec) {
            return (measureSpec & ~MODE_MASK);
        }
    }

03.View的测量流程

  • View的测量流程如下所示
    • img
      img

04.View的onMeasure源码

  • View中onMeasure方法已经默认为我们的控件测量了宽高,我们看看它做了什么工作:
    protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension( getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
    /**
     * 为宽度获取一个建议最小值
     */
    protected int getSuggestedMinimumWidth () {
        return (mBackground == null) ? mMinWidth : max(mMinWidth , mBackground.getMinimumWidth());
    }
    /**
     * 获取默认的宽高值
     */
    public static int getDefaultSize (int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec. getMode(measureSpec);
        int specSize = MeasureSpec. getSize(measureSpec);
        switch (specMode) {
        case MeasureSpec. UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec. AT_MOST:
        case MeasureSpec. EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }
  • 从源码可以知道:
    • 如果View的宽高模式为未指定,他的宽高将设置为android:minWidth/Height =”“值与背景宽高值中较大的一个;
    • 如果View的宽高 模式为 EXACTLY (具体的size ),最终宽高就是这个size值;
    • 如果View的宽高模式为EXACTLY (填充父控件 ),最终宽高将为填充父控件;
    • 如果View的宽高模式为AT_MOST (包裹内容),最终宽高也是填充父控件。
  • 也就是说如果我们的自定义控件在布局文件中,只需要设置指定的具体宽高,或者MATCH_PARENT 的情况,我们可以不用重写onMeasure方法。但如果自定义控件需要设置包裹内容WRAP_CONTENT ,我们需要重写onMeasure方法,为控件设置需要的尺寸;默认情况下WRAP_CONTENT 的处理也将填充整个父控件。

05.NestedScrollView测量过程

  • NestedScrollView是继承FrameLayout的控件,然后先看看onMeasure方法中的源码
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //通过super方法先测量父布局
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (this.mFillViewport) {
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            if (heightMode != 0) {
                if (this.getChildCount() > 0) {
                    //获取自布局,NestedScrollView下面只能嵌套一个线性布局或者相对布局。
                    View child = this.getChildAt(0);
                    LayoutParams lp = (LayoutParams)child.getLayoutParams();
                    int childSize = child.getMeasuredHeight();
                    int parentSpace = this.getMeasuredHeight() - this.getPaddingTop() - this.getPaddingBottom() - lp.topMargin - lp.bottomMargin;
                    if (childSize < parentSpace) {
                        int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, this.getPaddingLeft() + this.getPaddingRight() + lp.leftMargin + lp.rightMargin, lp.width);
                        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(parentSpace, 1073741824);
                        //测量子类child的控件
                        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }
                }
    
            }
        }
    }

06.看几个思考题分析

6.1 getWidth()方法和getMeasureWidth()

  • getWidth()方法和getMeasureWidth()区别是什么?
    • getMeasureWidth()
      • getMeasureWidth()方法在measure()过程结束后就可以获取到了,另外,getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的
      • 这里mMeasuredWidth & MEASURED_SIZE_MASK表示的是测量阶段结束之后,view真实的值。
      public final int getMeasuredWidth() {
          return mMeasuredWidth & MEASURED_SIZE_MASK;
      }
    • getWidth()
      • getWidth()方法要在layout()过程结束后才能获取到,getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。
      • mRight和mLeft是什么值,是在什么时候被设置的。具体看layout()过程中源码
      @ViewDebug.ExportedProperty(category = "layout")
      public final int getWidth() {
          return mRight - mLeft;
      }

6.2 getWidth()或者getMeasureWidth()得到0

  • 为什么有时候用getWidth()或者getMeasureWidth()得到0
    • 问题描述:使用getMeasuredWidth()和getMeasuredHeight()方法,无论是在onCreate()、onStart()、onResume()中调用,都无法得到控件的长度、和宽度。如下图,测量的结果为0。
    • 解释:技术博客大总结
      • 因为View的Measure过程和Activity的生命周期方法不是同步执行的,所以无法保证Activity执行了onCreate()、onStart()、onResume()时某个View已经测量完毕了,如果View还没有测量完毕,那么获得宽/高就是0。
  • 解决控件测量宽高问题
    • 如下所示
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test();
    }
    
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        getWidth(4);
    }
    
    private void test(){
        getWidth(1);
        
        marqueeView.measure(0, 0);
        getWidth(2);
        
        marqueeView.post(new Runnable() {
            @Override
            public void run() {
                getWidth(3);
            }
        });
    }
    
    private void getWidth(int a){
        int width2 = marqueeView.getWidth();
        int measuredWidth2 = marqueeView.getMeasuredWidth();
        Log.e(a+"MainActivity-----",width2+"-----"+measuredWidth2);
    }
    
    //11-28 17:03:17.559 15990-15990/com.yc.cn.ycbanner E/1MainActivity-----: 0-----0
    //11-28 17:03:17.567 15990-15990/com.yc.cn.ycbanner E/2MainActivity-----: 0-----760
    //11-28 17:03:17.684 15990-15990/com.yc.cn.ycbanner E/3MainActivity-----: 960-----960
    //11-28 17:03:17.685 15990-15990/com.yc.cn.ycbanner E/4MainActivity-----: 960-----960
  • 什么时候测量宽高不等于实际宽高?
    • MeasuredWidth/height!=getWidth/Height()的场景:更改View的布局参数并进行重新布局后,就会导致测量宽高!=实际宽高

07.View中onMeasure方法

  • 下面是真是开发案例中的代码,如下所示
    //Android7.0以后,优化了View的绘制,onMeasure和onSizeChanged调用顺序有所变化
    //Android7.0以下:onMeasure--->onSizeChanged--->onMeasure
    //Android7.0以上:onMeasure--->onSizeChanged
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        /*
         * onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值
         * MeasureSpec.EXACTLY 是精确尺寸
         * MeasureSpec.AT_MOST 是最大尺寸
         * MeasureSpec.UNSPECIFIED 是未指定尺寸
         */
    
        if (heightMode == MeasureSpec.EXACTLY) {
            heightSize = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
        } else if (heightMode == MeasureSpec.AT_MOST && getParent() instanceof ViewGroup
                && heightSize == ViewGroup.LayoutParams.MATCH_PARENT) {
            heightSize = MeasureSpec.makeMeasureSpec(((ViewGroup) getParent()).getMeasuredHeight(), MeasureSpec.AT_MOST);
        } else {
            int heightNeeded;
            if (gravity == Gravity.CENTER) {
                if (tickMarkTextArray != null && tickMarkLayoutGravity == Gravity.BOTTOM) {
                    heightNeeded = (int) (2 * (getRawHeight() - getTickMarkRawHeight()));
                } else {
                    heightNeeded = (int) (2 * (getRawHeight() - Math.max(leftSB.getThumbScaleHeight(), rightSB.getThumbScaleHeight()) / 2));
                }
            } else {
                heightNeeded = (int) getRawHeight();
            }
            heightSize = MeasureSpec.makeMeasureSpec(heightNeeded, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightSize);
    }
  • 下面是ImageView的源代码
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        resolveUri();
        int w;
        int h;
    
        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = 0.0f;
    
        // We are allowed to change the view's width
        boolean resizeWidth = false;
    
        // We are allowed to change the view's height
        boolean resizeHeight = false;
    
        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    
        if (mDrawable == null) {
            // If no drawable, its intrinsic size is 0.
            mDrawableWidth = -1;
            mDrawableHeight = -1;
            w = h = 0;
        } else {
            w = mDrawableWidth;
            h = mDrawableHeight;
            if (w <= 0) w = 1;
            if (h <= 0) h = 1;
    
            // We are supposed to adjust view bounds to match the aspect
            // ratio of our drawable. See if that is possible.
            if (mAdjustViewBounds) {
                resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
                resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
    
                desiredAspect = (float) w / (float) h;
            }
        }
    
        final int pleft = mPaddingLeft;
        final int pright = mPaddingRight;
        final int ptop = mPaddingTop;
        final int pbottom = mPaddingBottom;
    
        int widthSize;
        int heightSize;
    
        if (resizeWidth || resizeHeight) {
            /* If we get here, it means we want to resize to match the
                drawables aspect ratio, and we have the freedom to change at
                least one dimension.
            */
    
            // Get the max possible width given our constraints
            widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
    
            // Get the max possible height given our constraints
            heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
    
            if (desiredAspect != 0.0f) {
                // See what our actual aspect ratio is
                final float actualAspect = (float)(widthSize - pleft - pright) /
                                        (heightSize - ptop - pbottom);
    
                if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
    
                    boolean done = false;
    
                    // Try adjusting width to be proportional to height
                    if (resizeWidth) {
                        int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
                                pleft + pright;
    
                        // Allow the width to outgrow its original estimate if height is fixed.
                        if (!resizeHeight && !sCompatAdjustViewBounds) {
                            widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                        }
    
                        if (newWidth <= widthSize) {
                            widthSize = newWidth;
                            done = true;
                        }
                    }
    
                    // Try adjusting height to be proportional to width
                    if (!done && resizeHeight) {
                        int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
                                ptop + pbottom;
    
                        // Allow the height to outgrow its original estimate if width is fixed.
                        if (!resizeWidth && !sCompatAdjustViewBounds) {
                            heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
                                    heightMeasureSpec);
                        }
    
                        if (newHeight <= heightSize) {
                            heightSize = newHeight;
                        }
                    }
                }
            }
        } else {
            /* We are either don't want to preserve the drawables aspect ratio,
               or we are not allowed to change view dimensions. Just measure in
               the normal way.
            */
            w += pleft + pright;
            h += ptop + pbottom;
    
            w = Math.max(w, getSuggestedMinimumWidth());
            h = Math.max(h, getSuggestedMinimumHeight());
    
            widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
            heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
        }
    
        setMeasuredDimension(widthSize, heightSize);
    }

08.ViewGroup中onMeasure方法

  • 下面是真是开发案例中LinearLayout的代码,如下所示
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int myWidth = -1;
        int myHeight = -1;
    
        int width = 0;
        int height = 0;
    
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
        // Record our dimensions if they are known;
        if (widthMode != MeasureSpec.UNSPECIFIED) {
            myWidth = widthSize;
        }
    
        if (heightMode != MeasureSpec.UNSPECIFIED) {
            myHeight = heightSize;
        }
    
        if (widthMode == MeasureSpec.EXACTLY) {
            width = myWidth;
        }
    
        if (heightMode == MeasureSpec.EXACTLY) {
            height = myHeight;
        }
    
        View ignore = null;
        int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
        final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;
        gravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
        final boolean verticalGravity = gravity != Gravity.TOP && gravity != 0;
    
        int left = Integer.MAX_VALUE;
        int top = Integer.MAX_VALUE;
        int right = Integer.MIN_VALUE;
        int bottom = Integer.MIN_VALUE;
    
        boolean offsetHorizontalAxis = false;
        boolean offsetVerticalAxis = false;
    
        if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
            ignore = findViewById(mIgnoreGravity);
        }
    
        final boolean isWrapContentWidth = widthMode != MeasureSpec.EXACTLY;
        final boolean isWrapContentHeight = heightMode != MeasureSpec.EXACTLY;
    
        // We need to know our size for doing the correct computation of children positioning in RTL
        // mode but there is no practical way to get it instead of running the code below.
        // So, instead of running the code twice, we just set the width to a "default display width"
        // before the computation and then, as a last pass, we will update their real position with
        // an offset equals to "DEFAULT_WIDTH - width".
        final int layoutDirection = getLayoutDirection();
        if (isLayoutRtl() && myWidth == -1) {
            myWidth = DEFAULT_WIDTH;
        }
    
        View[] views = mSortedHorizontalChildren;
        int count = views.length;
    
        for (int i = 0; i < count; i++) {
            View child = views[i];
            if (child.getVisibility() != GONE) {
                LayoutParams params = (LayoutParams) child.getLayoutParams();
                int[] rules = params.getRules(layoutDirection);
    
                applyHorizontalSizeRules(params, myWidth, rules);
                measureChildHorizontal(child, params, myWidth, myHeight);
    
                if (positionChildHorizontal(child, params, myWidth, isWrapContentWidth)) {
                    offsetHorizontalAxis = true;
                }
            }
        }
    
        views = mSortedVerticalChildren;
        count = views.length;
        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
        
        //省略部分代码
    
        setMeasuredDimension(width, height);
    }

其他介绍

01.关于博客汇总链接

  • 1.技术博客汇总
  • 2.开源项目汇总
  • 3.生活博客汇总
  • 4.喜马拉雅音频汇总
  • 5.其他汇总

02.关于我的博客

  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yczbj/activities
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
  • 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
贡献者: yangchong211
上一篇
3.2View的绘制基础
下一篇
3.4onLayout流程设计