安卓绘制视图的流程

来源:互联网 发布:三下五除二软件 编辑:程序博客网 时间:2024/05/20 18:48

本文翻译自安卓官方文档 How Android Draws Views,简略的介绍视图的绘制过程,即 measure 过程和 layout 过程。

当一个 Activity 获得焦点之后,它会去绘制自己的视图。安卓系统框架会负责绘制过程,但是 Activity 必须提供自己视图树的根节点。

绘制流程从根节点开始。从根节点开始计算和绘制视图树。绘制的方法是遍历视图树然后渲染每个位于可见区的视图。按中序遍历(实际应为后续遍历,measure 是后续遍历,layout 和 draw 是前序遍历,因为子视图计算完成后才能计算父视图,而根据子视图覆盖在父视图上可以推测 draw 是后续遍历——译者注)的顺序,视图树中的每个父视图负责要求自己的子视图去进行绘制,每个子视图绘制自己。由于是中序遍历,所以父视图先于子视图被绘制,而兄弟关系的视图按照在视图树中出现的顺序进行绘制。

视图树的绘制包括 measure 和 layout 两个部分:

  • measure 过程在 measure(int, int) 方法中实现,而且是一个自顶向下(实际应为自顶向上——译者注)的过程;在递归过程中,每个视图都自顶向下将尺寸规则下发;在 measure 过程结束时,每个视图都保存了自己的计算结果;
  • layout 过程也是一个自顶向下的过程,具体实现在 layout(int, int, int, int) 方法中;在这个过程,每个父视图利用 measure 过程计算出的尺寸去放置子视图;

注意:系统框架不会绘制不在可见区内的视图对象,而且会绘制视图的背景。如果要强制绘制某个视图,要调用 invalidate() 方法。

一个视图对象的 measure() 方法执行完毕后,它的 getMeasuredWidth() 和 getMeasuredHeight() 方法的返回值也已经就绪;这个视图的子视图的也已经就绪(再次证明 measure 过程是后序遍历——译者注)。视图的宽高值必须要“尊重”父视图给的限制,这样才能保证 measure 过程结束时所有的父视图都接受父视图的计算结果。父视图可能不止一次调用 measure() 方法。For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children’s unconstrained sizes is too big or too small (that is, if the children don’t agree among themselves as to how much space they each get, the parent will intervene and set the rules on the second pass).

注意:调用 requestLayout() 去初始化一个布局。这个方法一般被视图调用,当视图认为其当前边界值已经无法满足需要。

measure 过程使用两个类来协商尺寸:ViewGroup.LayoutParams 和 View.MeasureSpec。视图使用ViewGroup.LayoutParams 来告诉其父视图它们如何被计算和摆放。ViewGroup.LayoutParams 基类仅仅描述视图想要多大的宽高。可以给宽或高赋以下值:

  • an exact number,一个具体值
  • MATCH_PARENT,和父视图一样大(不包括父视图的内边距)
  • WRAP_CONTENT,大到足够包括其内容(包括视图的内边距)

不同的 ViewGroup 的派生类都有自己的继承自 ViewGroup.LayoutParams 的子类。例如,RelativeLayout 就有自己的 RelativeLayout.LayoutParams,具有水平或竖直居中摆放子视图的能力。

View.MeasureSpec 对象用于被父视图自顶向下的下发给子视图。View.MeasureSpec 具有三种模式:

  • UNSPECIFIED:父视图用这个模式去确定子视图想要的尺寸;例如,一个拥有一个高是 UNSPECIFIED 宽是 240 的子视图的 LinearLayout 会对该子视图调用 measure() 方法,以确定该子视图在宽为240像素时想要多大的高;
  • EXACTLY:父视图使用该值告诉子视图必须要使用这个值,并且子视图保证其所有的子视图满足这个尺寸;
  • AT_MOST: 父视图使用该值告诉子视图其最大值,子视图必须保证它和它的子视图满足这个尺寸。
0 0