【Android】View绘制过程分析之measure
来源:互联网 发布:mac登陆界面变英文 编辑:程序博客网 时间:2024/06/11 05:18
读源码,分析View的绘制过程,对自定义View的开发与理解有莫大的帮助。这是写本组文章的目的所在!
绘制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 - 原创文章,转载请注明出处
0 0
- 【Android】View绘制过程分析之measure
- 【Android View绘制之旅】Measure过程
- View绘制之measure过程
- 【Android系列】View的绘制之measure过程
- android view绘制流程之Measure
- Android中View绘制流程:measure过程,layout过程
- 【Android】View绘制过程分析之layout
- 【Android】View绘制过程分析之draw
- Android View的绘制之 从源码了解measure的过程。
- Android View measure过程
- View的绘制流程分析之二 -- measure
- Android中View的绘制原理之measure
- android学习9#--自定义View之绘制过程分析
- android绘制view的过程之一---------计算view大小(measure)
- android绘制view的过程之一---------计算view大小(measure)
- android绘制view的过程之一---------计算view大小(measure)
- android绘制view的过程之一---------计算view大小(measure)
- android绘制view的过程之一---------计算view大小(measure)(转)
- Ubuntu上使用Hadoop 2.x 三 编译2.2.0 64bit版本
- Android make sdk出错问题的解决
- POJ 3358 Period of an Infinite Binary Expansion
- hdu 1711 Number Sequence
- spring IOC 实现原理模拟实现
- 【Android】View绘制过程分析之measure
- 386高校毕业设计选题
- POJ 2456 Aggressive cows 二分
- 黑马程序员__java(5)__面向对象
- String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
- 【SCOI2004】文本的输入
- spring IOC原理
- 使用FlashCS6制作cocos2d-x动作脚本的思路整理
- hdu 2604 Queuing(矩阵乘法)