http://blog.csdn.net/tianjf0514/article/details/7752823
View可以看成一个树形结构,父控件是父节点,子控件是子节点。View的绘制过程就是遍历这棵树。
View的绘制有三步:
- measure:测量View的Width和Height,
- layout:布局View(left,right,top,bottom),指定View和手机屏幕的上下左右的距离。
- draw:绘图
以上的步骤必须按照顺序来。(顺便说一下,以上三个步骤发生在View的构造方法之后。)
一、measure
measure是绘制视图的第一步,因为只有知道的View的大小(Width和Height)才能绘图。
我们在编写layout的xml文件的时候,会遇到layout_width和layout_height两个属性,对于这两个属性我们有三个选择:fill_parent、wrap_content和具体值,measure就是用来处理fill_parent、wrap_content两个属性的,在绘图的时候,要知道具体的值,所以要计算fill_parent、wrap_content的具体值。
下面是几个重要的函数和参数:
- public final void measure(int widthMeasureSpec, int heightMeasureSpec)
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)
- protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
- protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)
前两个方法是View类里面的方法,后三个方法是ViewGroup类里面的方法。
先来看看measure的源码:
- /**
- * <p>
- * This is called to find out how big a view should be. The parent
- * supplies constraint information in the width and height parameters.
- * </p>
- *
- * <p>
- * The actual mesurement work of a view is performed in
- * {@link #onMeasure(int, int)}, called by this method. Therefore, only
- * {@link #onMeasure(int, int)} can and must be overriden by subclasses.
- * </p>
- *
- *
- * @param widthMeasureSpec Horizontal space requirements as imposed by the
- * parent
- * @param heightMeasureSpec Vertical space requirements as imposed by the
- * parent
- *
- * @see #onMeasure(int, int)
- */
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
- widthMeasureSpec != mOldWidthMeasureSpec ||
- heightMeasureSpec != mOldHeightMeasureSpec) {
- // first clears the measured dimension flag
- mPrivateFlags &= ~MEASURED_DIMENSION_SET;
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
- }
- // measure ourselves, this should set the measured dimension flag back
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- // flag not set, setMeasuredDimension() was not invoked, we raise
- // an exception to warn the developer
- if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
- throw new IllegalStateException("onMeasure() did not set the"
- + " measured dimension by calling"
- + " setMeasuredDimension()");
- }
- mPrivateFlags |= LAYOUT_REQUIRED;
- }
- mOldWidthMeasureSpec = widthMeasureSpec;
- mOldHeightMeasureSpec = heightMeasureSpec;
- }
measure方法是final类型的,所以不能被继承,不能被复写。而measure方法里面调用了onMeasure方法,onMeasure方法可以被继承,可以被复写。下面是onMeasure源码:
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
onMeasure默认的实现仅仅调用了setMeasuredDimension,setMeasuredDimension函数是一个很关键的函数,它对View的成员变量mMeasuredWidth和mMeasuredHeight变量赋值,而measure的主要目的就是对View树中的每个View的mMeasuredWidth和mMeasuredHeight进行赋值,一旦这两个变量被赋值,则意味着该View的测量工作结束。
setMeasuredDimension源码如下:
- protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
- mMeasuredWidth = measuredWidth;
- mMeasuredHeight = measuredHeight;
- mPrivateFlags |= MEASURED_DIMENSION_SET;
- }
再来看下MeasureSpec这个类,MeasureSpec参数的值为int型,分为高32位和低16为,高32位保存的是specMode,低16位表示specSize,specMode分三种:
- MeasureSpec.UNSPECIFIED:父视图不对子视图施加任何限制,子视图可以得到任意想要的大小
- MeasureSpec.EXACTLY:父视图希望子视图的大小是specSize中指定的大小
- MeasureSpec.AT_MOST:子视图的大小最多是specSize中的大小
以上施加的限制只是父视图“希望”子视图的大小按MeasureSpec中描述的那样,但是子视图的具体大小取决于多方面的