【Android】View绘制过程分析之measure
2014-02-22 00:17
375 查看
读源码,分析View的绘制过程,对自定义View的开发与理解有莫大的帮助。这是写本组文章的目的所在!
绘制View的过程分为3个阶段:
第1阶段,measure() 计算View应占空间大小
第2阶段,layout() 分配大小和位置到View及它的子View
第3阶段,draw() 绘制
首先,分析第1阶段,分析过程的注释标记在以下代码中。
@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处
绘制View的过程分为3个阶段:
第1阶段,measure() 计算View应占空间大小
第2阶段,layout() 分配大小和位置到View及它的子View
第3阶段,draw() 绘制
首先,分析第1阶段,分析过程的注释标记在以下代码中。
/** * 通过这个方法来计算View应该占多大的空间, * 父View通过widthMeasureSpec和heightMeasureSpec这两个参数来约束了此View的空间大小 * 实际的计算工作在onMeasure(int,int)方法中实现,子类应该覆写onMeasure(int,int)方法方法提供确切的大小 */ public final void measure(int widthMeasureSpec, int heightMeasureSpec) { if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); // 子类只需要覆写onMeasure(int,int)方法,来做计算View空间的相关工作 onMeasure(widthMeasureSpec, heightMeasureSpec); //子类必须(在onMeasure(int,int)方法中)调用setMeasuredDimension()方法,否则抛IllegalStateException异常 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { throw new IllegalStateException("onMeasure() did not set the" + " measured dimension by calling" + " setMeasuredDimension()"); } mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; } mOldWidthMeasureSpec = widthMeasureSpec; mOldHeightMeasureSpec = heightMeasureSpec; } /** * 计算此View和它的内容应占的空间大小。 * 注意1:在此方法中一定要调用setMeasuredDimension(int,int)来设置此View应占的大小 * 注意2:若是此View是布局,则要遍历所有子View,调子View的measure(int, int)方法为子View计算大小 * View类onMeasure(int, int)方法的默认实现如下: */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { //getMeasuredWidth()和getMeasuredHeight()方法获取到的就是在这里设置的值 mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; //或运算,标记已经调用过setMeasuredDimension(int,int)方法,在measure(int,int)方法中通过与运算来判断 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; } /** * 用于获取默认大小的工具方法 * 若父View有约束此View大小(通过measureSpec),则遵循父View分配的大小; * 否则以传进来的参数size作为大小。size怎么得来?且继续看下去。 */ public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; } /** * 获取建议View应该使用的最小宽度。取值为“mMinWidth”和“背景图片最小宽度”两者中的最大值。 * 其中mMinWidth从哪里来?使用时,一是通过调用setMinimumWidth(int)方法设置;二是通过布局文件中属性android:minWidth设置 * */ protected int getSuggestedMinimumWidth() { return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); } /** * Drawable类的方法,若Drawable是图片资源,有固定的宽度,则返回固定的宽度;否返回0 */ public int getMinimumWidth() { final int intrinsicWidth = getIntrinsicWidth(); return intrinsicWidth > 0 ? intrinsicWidth : 0; } /** * getSuggestedMinimumHeight(int,int)方法同理,略。 */ /** * 若是此View是布局,以FrameLayout为例: */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //省略部分代码 //设置自己的大小 setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); //遍历子View,计算子View的大小 count = mMatchParentChildren.size(); if (count > 1) { for (int i = 0; i < count; i++) { final View child = mMatchParentChildren.get(i); final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); //以下操作,创建MeasureSpec传递给子View, 即FrameLayout给子View分配大小 int childWidthMeasureSpec; int childHeightMeasureSpec; if (lp.width == LayoutParams.MATCH_PARENT) { //子View的宽度 = 父View的宽度 - 父View的Padding - 子View的Margin childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeftWithForeground() - getPaddingRightWithForeground() - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY); } else { childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeftWithForeground() + getPaddingRightWithForeground() + lp.leftMargin + lp.rightMargin, lp.width); } if (lp.height == LayoutParams.MATCH_PARENT) { childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTopWithForeground() - getPaddingBottomWithForeground() - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY); } else { childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTopWithForeground() + getPaddingBottomWithForeground() + lp.topMargin + lp.bottomMargin, lp.height); } //调用子View的measure(int, int)方法。 //根据上面的计算得知:子View的measure()方法中得到的childWidthMeasureSpec不包括子View的Margin值 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } } /** * 来看一下MeasureSpec类的工具方法: * 参数size为实际大小值, * 参数mode为模式,可取值: * EXACTLY(父View确切地给定了子View的大小,不顾View可能超出这个大小) * AT_MOST(尽可能大, The child can be as large as it wants up to the specified size.) * UNSPECIFIED(父View没有约束子View的大小,子View想要多大就多大) */ public static int makeMeasureSpec(int size, int mode) { if (sUseBrokenMakeMeasureSpec) { return size + mode; //原来是实际大小值与模式值之和 } else { return (size & ~MODE_MASK) | (mode & MODE_MASK); } }
@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处
相关文章推荐
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- Android View的绘制之 从源码了解measure的过程。
- Android中measure过程、view绘制原理和MeasureSpec介绍及使用详解
- Android中View的绘制过程 onMeasure方法简述
- android中View绘制过程分析
- android绘制view的过程之一---------计算view大小(measure)
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- android绘制view的过程之一---------计算view大小(measure)
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android中View的绘制过程 onMeasure方法简述
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android中View和ViewGroup的measure和layout过程分析
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- android绘制view的过程之一---------计算view大小(measure)
- 【Android系列】View的绘制之measure过程
- android绘制view的过程之一计算view大小(measure)
- 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子