控件的工作流程

控件的工作流程主要是指measure、layout和draw三大流程,即控件的测量、布局和绘制。其中measure确定控件的测量宽/高,layout确定控件的最终宽/高和四个顶点的位置,draw将View绘制到屏幕上。

View的测量

Android系统在绘制View前,要对View进行测量,告诉系统View的大小,这个过程是在View的onMeasure()方法中进行的。

具体测量View是通过MeasureSpec类,测量模式有一下三种:

  • EXACTLY
    当控件的layout_width和layout_height属性为具体数值,或者被指定为match_parent时,使用的就是该模式;

  • AT_MOST
    当控件的layout_width和layout_height属性被指定为wrap_content时使用,这时控件的大小会随着子控件的大小变化,同时控件的尺寸不允许超过父控件的最大尺寸;

  • UNSPECIFIED
    在这个模式下,View大小可以随意指定,通常在绘制自定义View的时候使用;

MeasureSpec类除了指定View的测量模式外,还指定了对应测量模式下View的尺寸。

MeasureSpec是一个32位的int值,其中高2位为测量的模式,低30位为测量的大小,为了提高运算效率,具体获取模式和大小的时候使用位运算。

View的默认onMeasure()方法只支持EXACTLY模式,如果想让View支持wrap_content属性,需要重写onMeasure()方法,指定AT_MOST模式下View的大小。

View的绘制

View测量完毕后,需要重写onDraw()方法,在其Canvas对象上使用Paint对象绘制所需的图形。可以把Canvas对象看作成一块画板,Paint对象看作画笔,然后在onDraw()方法中进行绘制操作。

调用Canvas的drawXXX()方法绘制图形、文字、图片等,对于复杂的控件,可以把其拆分为一个个小的图形单元分别绘制。

ViewGroup的测量

ViewGroup在测量时,会遍历所有的子View,调用子View的measure()方法获取每个子View的测量结果,这时子View会调用onMeasure()方法进行测量。

类似于View,如果需要支持wrap_content属性,也需要重写onMeasure()方法。

ViewGroup的布局

当子View测量完毕后,还需要把子View放到合适的位置,这个过程就是ViewGroup的布局过程。ViewGroup在执行布局过程时,同样会遍历调用子View的layout()方法,然后子View调用onLayout()方法进行具体的布局过程。在布局过程中,layout()方法确定View本身的位置,而onLayout()方法确定所有子View的位置。

在自定义ViewGroup时,通常需要重写onLayout()方法来控制其子View的显示位置。

ViewGroup的绘制

ViewGroup通常不需要绘制,因为其本身没有需要绘制的内容,如果不指定背景颜色,ViewGroup的onDraw()方法都不会被调用。但是,ViewGroup会使用dispatchDraw()方法来绘制其子View,这个过程也会遍历所有的子View,并调用子View的draw()方法完成绘制工作。

坚持原创技术分享,您的支持将鼓励我继续创作!