界面优化1——View绘制机制

247 阅读3分钟

一、 view树的绘制流程

当anctivity接收到用户的触摸焦点时,会被请求绘制布局,这个请求时由android的framWork层来处理的。处理方法是从根节点开始测量和绘制。整个绘制流程是通过measure、layout和draw三个方法来实现的。

measure -> layout -> draw

  • measure: 是否重新计算视图大小
  • layout: 是否需要重新安置视图的位置
  • draw: 是否需要重绘

总结:view树的绘制流程就像是一个递归过程,在onMeasure方法里,它的view会对所有它的子元素进行测量,测量过程就从它的父的viewGroup传递到了它的子view里面,经过子元素的递归,测量好了所有子元素的长度,然后进行递归,反复之后,就完成了整个父元素viewGroup的测量。而Layout 也是类似,树的递归过程。

二、 measure

measure的测量是一个树的递归过程,从上到下有序的进行遍历,根据父容器对子容器的测量规格及参数获取到子容器的长宽高,然后把子容器的长宽高返还给父容器进行统一的测量。

2.1 measure-重要参数

  1. ViewGroup.LayoutParams: 用来制定视图宽度和高度的参数,可以设置三种值,具体的值/match_parent/wrap_content。
  2. MeasureSpec: 测量规格,32位的int值,最高的2位表示spec_mode,是模式占位符,后面的30位表示测量规格的大小(在这种测量模式下尺寸的大小),在view空间Measure的过程中,系统将该View的LayoutParams结合父容器生成一个MeasureSpec,该MeasureSpec测量规格会规定好怎样去测量该View控件的大小。不管是ViewGroup.LayoutParams还是其他的大小,最终都会包装成MeasureSpec测量规格,然后返还给父容器,告诉父容器如何测量该View的空间大小。

mode 主要分为3类,分别是

  • EXACTLY:父容器已经测量出子View的大小。对应是 View 的LayoutParams的match_parent 或者精确数值。
  • AT_MOST:父容器已经限制子view的大小,View 最终大小不可超过这个值。对应是 View 的LayoutParams的wrap_content
  • UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。(这种不怎么常用)

2.2 measure-重要方法

  1. measure
    在measure 方法,核心就是调用onMeasure( ) 进行View的测量。在自定义时,只要复写onMeasure方法就可以了
  2. onMeasure
  • 参数1: widthMeasureSpec 宽的测量规格
  • 参数2: heightMeasureSpec 高的测量规格
  1. setMeasureDimension
    调用setMeasureDimension方法,该方法是测量阶段的终极,也是实现onMeasure的方法。

三、 layout

和measure是一样的,通过对view树的自上而下进行遍历,根据测量得到的尺寸来摆放子视图的位置,需要明确的是,子视图的具体位置都是相对父视图而言的。所以说view的onLayout方法是一个空实现。如果自定义view需要继承viewGroup,则必须实现onLayout方法,然后重新摆放自己想要自定义view的位置,在layout方法中,最终调用onLayout方法,ViewGroup的onLayout是一个抽象的实现了, 所以子View必须实现onLayout方法。

四、 draw

两个容易混淆的方法

  1. invalidate()
    调用时请求android系统,如果视图大小没有发生变化,则不会调用layout放置这个过程,
  2. requestLayout()
    当布局发生变化时,如方向或尺寸变化时,就会调用requestLayout方法,在自定义视图中,经常会调用该方法,需要重新测量尺寸时就会手动调用该方法,调用方法后,会触发measure和layout过程,但是不会调用draw方法。

参考资料
Android View的绘制流程