计算视图大小(measure)的过程

原创 2013年12月05日 16:25:36

视图是无穷大的,layout_wdith和layout_height是指父视图分配给子视图的布局大小。

视图分两类,内容型视图和图形型视图。

内容型视图的布局大小一般由内容的多少决定。

图形型视图的布局大小一般由父视图给子视图分配的布局大小决定。

1、measure内部调用过程分析


上图中了描述了measure的调用过程,分析如下:

(1)过程开始于ViewRoot类中的performTraversals()

(2)performTraversals()方法中调用host.measure()

(3)首先host是一个View对象,在measure()方法中调用到onMeasure(),host一般是一个ViewGroup的实例,如LinearLayout就重载了onMeasure()方法

(4)在LinearLayout中的onMeasure()方法中,碾转调用到了父类ViewGroup的measureChildWithMargins()

(5)在ViewGroup的measureChildWithMargins()中又会调用到child.measure()方法

(6)如果child仍然是一个ViewGroup的实例,接着进行(3)~(5)步骤

(7)如果child是一个常规View对象,则调用View类的onMeasure()方法,通过setMeasuredDimension()设定该View对象测量出来的布局大小。

measure()方法中的参数是父视图给子视视图的规格,转换为32位二进制数,最高两位代表了specMode,后30位代表了specSize

specMode有三种

(a)MeasureSpec.EXACTLY确定的,最好是遵守父视图给你“确定”下来的布局大小。

(b)MeasureSpec.AT_MOST最多,最好不要超过父视图给你的布局大小。

(c)MeasureSpec.UNSPECIFIED没有限制,根据自己的需求确定你的视图的大小。

2、ViewGroup中的measureChildWithMargins

    protected void measureChildWithMargins(View child,
            int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
                        + heightUsed, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

以ViewGroup的实例为LinearLayout对上面的代码分析如下:

(1)调用child.getLayoutParams(),getLayoutParams()方法是在View类中定义的,返回类型是ViewGroup.LayoutParams,对象名称是mLayoutParams

(2)MarginLayoutParams是ViewGroup.LayoutParams的子类,这里将ViewGroup.LayoutParams类型对象强转为了MarginLayoutParams类型对象,即是将父类转子类,这是为什么呢?只有一个解释就是child.getLayoutParams()返回的对象类型本身就是MarginLayoutParams的子类。

(3)那么getLayoutParams()返回的这个对象mLayoutParams,是在什么时候生成的呢?是在ViewGroup的addView()方法中。

    public void addView(View child, int index) {
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
    }
刚添加View对象时,params是空的,是调用generateDefaultLayoutParams()生成的。一般ViewGroup的实例如LinearLayout是重载了generateDefaultLayoutParams()方法的。该方法返回的类型是LinearLayout.LayoutParams,该类正是MarginLayoutParams的子类。

(4)在addViewInner()方法中,通过child.mLayoutParams = params,把上一步generateDefaultLayoutParams()生成的对象赋值给了mLayoutParams
(5)综上,child.getLayoutParams()返回的对象是LinearLayout.LayoutParams类型,印证了(2)中的解释。

(6)两次调用getChildMeasureSpec(int spec, int padding, int childDimension)计算出子视图的宽高,从参数可以看出,子视图的大小是由父视图提供的规格和子视图期望得到的大小共同决定,当然还有padding

(7)接着调用child.measure()来征询子视图期望布局大小的意愿,子视图可以重载onMeasure()方法,并调用setMeasureDimension()函数来最终敲定布局大小。

 3、LinearLayout中的onMeasure()过程

View中的measure()方法不能重载,以保证View系统中的基本测量流程,ViewGroup的实例一般需要重载onMeasure()函数,来配合View的measure过程的完成。

在LinearLayout.onMeasure()方法中,首先判断是水平还是垂直,我们分析垂直 的情况

(1)final int count = getVirtualChildCount()计算出子视图个数

(2)调用两次MeasureSpec.getMode()计算出宽高模式

(3)用一个for循环计算出所有子视图的高度,用一个变量mTotalLength保存

(4)在for循环中调用了measureChildBeforeLayout()对每一个进行测量,该函数实际调用了ViewGroup中的measureChildWithMargins()函数。

(5)在步骤中暂时避过了lp.wight>0的子视图,后面父视图将剩余高度按照weight大小均匀分配给相应的子视图



版权声明:本文为博主原创文章,未经博主允许不得转载。

Android自定义视图系列----------- 计算view大小(measure)

1.android绘制view的过程简单描述            简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw);            下面看...
  • zhoupenglei
  • zhoupenglei
  • 2015年01月06日 11:11
  • 739

View工作原理(三)视图大小计算过程(measure过程)

一、android中view的measure过程总概 视图大小计算的过程是从根视图measure()方法开始,接着该方法会调用根视图的onMeasure()方法,onMeasure()方法会对所包...
  • judyge
  • judyge
  • 2016年01月13日 17:17
  • 203

View工作原理(三)视图大小计算过程(measure过程)

一、android视图measure过程总概 视图大小计算的过程是从根视图measure()方法开始,接着该方法会调用根视图的onMeasure()方法,onMeasure()方法会对所包含的子视图...
  • ff20081528
  • ff20081528
  • 2013年12月25日 18:20
  • 9421

android-View工作原理(三)视图大小计算过程(measure过程)

本文转载自:http://xixinfei.iteye.com/blog/2114701一、android中view的measure过程总概 视图大小计算的过程是从根视图measure()方...
  • u012424449
  • u012424449
  • 2016年06月06日 15:33
  • 162

源码解析Android中View的measure量算过程

View的measure方法还是比较聪明的,知道如何偷懒利用以前量算过的数据,如果情况有变,那么就调用onMeasure方法进行实际的量算工作,在onMeasure中,View要根据父ViewGrou...
  • sunqunsunqun
  • sunqunsunqun
  • 2015年10月25日 14:08
  • 9154

计算view大小(measure)

1.android绘制view的过程简单描述            简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw);            下面看...
  • zsg88
  • zsg88
  • 2013年09月24日 16:40
  • 764

Android进阶——Android视图工作机制之measure、layout、draw

前言 自定义View一直是初学者们最头疼的事情,因为他们并没有了解到真正的实现原理就开始试着做自定义View,碰到很多看不懂的代码只能选择回避,做多了会觉得很没自信。其实只要了解了View的工作机制...
  • qq_30379689
  • qq_30379689
  • 2017年01月23日 17:35
  • 2600

android绘制view的过程之一---------计算view大小(measure)(转)

1.android绘制view的过程简单描述            简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw);            下...
  • wendan564447508
  • wendan564447508
  • 2016年10月13日 15:05
  • 87

android绘制view的过程之一计算view大小(measure)

 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=200062&extra=page%3D1&page=1 1.android...
  • qq_21709449
  • qq_21709449
  • 2015年04月06日 17:47
  • 231

android绘制view的过程之一---------计算view大小(measure)(转)

http://www.eoeandroid.com/forum.php?mod=viewthread&tid=200062&extra=page%3D1&page=1  1.android绘制vie...
  • u011045817
  • u011045817
  • 2014年11月27日 23:14
  • 240
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:计算视图大小(measure)的过程
举报原因:
原因补充:

(最多只允许输入30个字)