Android中View的绘制过程 onMeasure方法

Android中View的绘制过程

当Activity获得焦点时,它将被要求绘制自己的布局,Android framework将会处理绘制过程,Activity只需提供它的布局的根节点。

  绘制过程从布局的根节点开始,从根节点开始测量和绘制整个layout tree。
  每一个ViewGroup 负责要求它的每一个孩子被绘制,每一个View负责绘制自己。
  因为整个树是按顺序遍历的,所以父节点会先被绘制,而兄弟节点会按照它们在树中出现的顺序被绘制。
  
  绘制是一个两遍(two pass)的过程:一个measure pass和一个layout pass。
  测量过程(measuring pass)是在measure(int, int)中实现的,是从树的顶端由上到下进行的。
  在这个递归过程中,每一个View会把自己的dimension specifications传递下去。
  在measure pass的最后,每一个View都存储好了自己的measurements,即测量结果。
  布局过程(layout pass),它发生在 layout(int, int, int, int)中,仍然是从上到下进行(top-down)。
  在这一遍中,每一个parent都会负责用测量过程中得到的尺寸,把自己的所有孩子放在正确的地方。


尺寸的父子关系处理

当一个View对象的 measure() 方法返回时,它的 getMeasuredWidth() 和 getMeasuredHeight()值应该被设置好了,并且它的所有子孙的值也应该一起被设置好了。
一个View对象的measured width 和measured height的值必须考虑到它的父容器给它的限制。
这样就保证了在measure pass的最后,所有的parent都接受了它的所有孩子的measurements结果。
注意:一个parent可能会不止一次地对它的孩子调用measure()方法。
比如,第一遍的时候,一个parent可能测量它的每一个孩子,并没有指定尺寸,parent只是为了发现它们想要多大;
如果第一遍之后得知,所有孩子的无限制的尺寸总和太大或者太小,parent会再次对它的孩子调用measure()方法,这时候parent会设定规则,介入这个过程,使用实际的值。 (即,让孩子自由发展不成,于是家长介入)。

布局属性说明

LayoutParams是View用来告诉它的父容器它想要怎样被放置的参数。
  最基本的LayoutParams基类仅仅描述了View想要多大,即指明了尺寸属性。即View在XML布局时通常需要指明的宽度和高度属性。
  每一个维度都可以指定成下列三种值之一:
  1.FILL_PARENT (API Level 8之后重命名为MATCH_PARENT),表示View想要尽量和它的parent一样大(减去边距)。
  2.WRAP_CONTENT,表示View想要刚好大到可以包含它的内容(包括边距)。
  3.具体的数值
  ViewGroup的不同子类(不同的布局类)有相应的LayoutParams子类,其中会包含更多的布局相关属性。

onMeasure方法

onMeasure方法是测量view和它的内容,决定measured width和measured height的,这个方法由 measure(int, int)方法唤起,子类可以覆写onMeasure来提供更加准确和有效的测量。
  有一个约定:在覆写onMeasure方法的时候,必须调用 setMeasuredDimension(int,int)来存储这个View经过测量得到的measured width and height。
  如果没有这么做,将会由measure(int, int)方法抛出一个IllegalStateException。
  onMeasure方法的声明如下:
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
   其中两个输入参数:
  widthMeasureSpec
  heightMeasureSpec

  分别是parent提出的水平和垂直的空间要求。
  这两个要求是按照View.MeasureSpec类来进行编码的。
  参见View.MeasureSpec这个类的说明:这个类包装了从parent传递下来的布局要求,传递给这个child。
  每一个MeasureSpec代表了对宽度或者高度的一个要求。
  每一个MeasureSpec有一个尺寸(size)和一个模式(mode)构成。
  MeasureSpecs这个类提供了把一个<size, mode>的元组包装进一个int型的方法,从而减少对象分配。当然也提供了逆向的解析方法,从int值中解出size和mode。

  有三种模式:

  UNSPECIFIED,这说明parent没有对child强加任何限制,child可以是它想要的任何尺寸。
  EXACTLY,Parent为child决定了一个绝对尺寸,child将会被赋予这些边界限制,不管child自己想要多大。
  AT_MOST,Child可以是自己任意的大小,但是有个绝对尺寸的上限。

  覆写onMeasure方法的时候,子类有责任确保measured height and width至少为这个View的最小height和width。
  (getSuggestedMinimumHeight() and getSuggestedMinimumWidth())。


onLayout

  这个方法是在layout pass中被调用的,用于确定View的摆放位置和大小。方法声明:
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
   其中的上下左右参数都是相对于parent的。如果View含有child,那么onLayout中需要对每一个child进行布局。

android的API Demo中有一个LabelView的类可以作为参考。









阅读更多
换一批

没有更多推荐了,返回首页