计算视图大小(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大小均匀分配给相应的子视图



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

相关文章推荐

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

一、android视图measure过程总概 视图大小计算的过程是从根视图measure()方法开始,接着该方法会调用根视图的onMeasure()方法,onMeasure()方法会对所包含的子视图...

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

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

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

转载连接

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

出处:http://www.eoeandroid.com/thread-200062-1-1.html 1.android绘制view的过程简单描述            简单描述可以解释为:计算...

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

发表于 2012-9-14 15:19:27 |只看该作者 |倒序浏览 0 1.android绘制view的过程简单描述    ...
  • lcpajj
  • lcpajj
  • 2013年01月07日 18:52
  • 417

view工作原理-计算视图大小的过程(onMeasure)

view的视图有两种情况: 内容型视图:由视图的内容决定其大小。 图形型视图:父视图为view动态调整大小。 ### measure的本质 把视图布局使用的“相对值”转化成具体值的过程,即把...

Android 从0开始自定义控件之 View 的 measure 过程(七)

> 转载请标明出处: [http://blog.csdn.net/airsaid/article/details/53678640](http://blog.csdn.net/airsaid/arti...
  • Airsaid
  • Airsaid
  • 2016年12月15日 23:10
  • 1916

【自定义view系列】View的measure过程

View的测量过程是三大流程中最复杂的。 在现实生活中,如果我们要去画一个图形,就必须知道他的大小和位置。测量(测量view的宽和高),知道view的大小。一.LayoutParams  Layou...
  • a910626
  • a910626
  • 2016年05月31日 15:37
  • 673

【Android】View绘制过程分析之measure

读源码,分析View的绘制过程,对自定义View的开发与理解有莫大的帮助。这是写本组文章的目的所在! 绘制View的过程分为3个阶段: 第1阶段,measure() 计算View应占空间大小第2阶...
  • rongxh7
  • rongxh7
  • 2014年02月22日 00:17
  • 1536

从源码分析View的measure过程

measure过程要分情况来看,如果只是一个原始的View,那么通过measure方法就完成了其测量过程,如果是一个ViewGroup,除了需要完成自己的测量外,还会遍历去掉用所有子元素的measur...
  • mChenys
  • mChenys
  • 2016年08月27日 16:56
  • 561
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:计算视图大小(measure)的过程
举报原因:
原因补充:

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