Android View 绘制流程之测量(一)
来源:互联网 发布:php设为首页代码 编辑:程序博客网 时间:2024/05/16 23:58
View树的绘制流程是从ViewRoot的performTraversals()开始的,树的遍历是有序的,由父视图到子视图,每一个 ViewGroup 负责绘制它所有的子视图,而最底层的 View 会负责测绘自身。ViewRootImpl是ViewRoot的实现类,在ViewRootImpl的performTraversals中顺序调用了performMeasure()、performLayout()、performDraw()三个方法,分别对应测量、布局、绘制三个过程。
1、测量
ViewRootImpl的performMeasure()调用了View的measure()方法,此方法为 final 类型,不可被复写,但 measure 调用链最终会回调 View/ViewGroup 对象的 onMeasure()方法。
如果ViewGroup中包含多个子View,则每个子View都要测量一次,ViewGroup中的measureChildren()负责测量子视图的大小:
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { final int size = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } }
measureChildren()遍历子视图后,调用了measureChild()方法测量每一个子视图,measureChild()方法又调用了View的measure()方法。
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
View的measure()方法接收两个参数,childWidthMeasureSpec和childHeightMeasureSpec,这两个值分别用于确定视图宽高的规格和大小。
MeasureSpecs 是测量的规格,包含测量要求和尺寸的信息,其值由specSize和specMode共同组成的,有三种模式:
UNSPECIFIED
父视图不对子视图有任何约束,它可以达到所期望的任意尺寸。比如 ListView、ScrollView,一般自定义 View 中用不到,
EXACTLY
父视图为子视图指定一个确切的尺寸,而且无论子视图期望多大,它都必须在该指定大小的边界内,对应的属性为 match_parent 或具体值,比如 100dp,父控件可以通过MeasureSpec.getSize(measureSpec)直接得到子控件的尺寸。
AT_MOST
父视图为子视图指定一个最大尺寸。子视图必须确保它自己所有子视图可以适应在该尺寸范围内,对应的属性为 wrap_content,这种模式下,父控件无法确定子 View 的尺寸,只能由子控件自己根据需求去计算自己的尺寸,这种模式就是我们自定义视图需要实现测量逻辑的情况。
onMeasure()才是测量View大小的地方,会调用getDefaultSize()来获取View的大小:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
getDefaultSize()根据MeasureSpec获取视图的宽高:
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宽高设置给setMeasuredDimension(),setMeasuredDimension()调用了setMeasuredDimensionRaw(),把宽高赋值给mMeasuredWidth、mMeasuredHeight;
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int opticalWidth = insets.left + insets.right; int opticalHeight = insets.top + insets.bottom; measuredWidth += optical ? opticalWidth : -opticalWidth; measuredHeight += optical ? opticalHeight : -opticalHeight; } setMeasuredDimensionRaw(measuredWidth, measuredHeight); }
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; }
至此,View的测量过程结束,此时调用View的getMeasuredWidth()、getMeasuredHeight()可以获得测量的宽高。
- Android View 绘制流程之测量(一)
- Android自定义View之绘制、测量
- 深入理解 Android 之 View 的绘制流程(一)
- Android学习笔记(一) View、ViewGroup的测量绘制
- view的流程(测量,布局,绘制)
- View、ViewGroup的测量、布局、绘制流程
- Android view的绘制流程(一)
- Android View之测量
- Android GUI之View绘制流程
- Android 之 View 的绘制流程
- Android之View的绘制流程
- android view绘制流程之Measure
- Android自定义View解析之View的绘制流程(一)
- 自定义控件(一):View的测量及绘制流程、原理简介
- Android View绘制流程
- Android View绘制流程
- Android View绘制流程
- Android View绘制流程
- SPDY
- centos 7下安装rabbitmq
- Linux命令之"date"
- 基本数据类型长度 以及 int,long 类型占字节数相同原因
- ubuntu下如何查看postgresql的运行日志
- Android View 绘制流程之测量(一)
- SpringMVC-提高篇-前台
- linux vi详解
- hiho hiho一下第三周 #1015 : KMP算法
- angularjs的http请求后台收不到数据
- Codeforces 624D Array Gcd(数论+dp)
- Web文件上传方法总结大全
- uafxcwd.lib(afxglobals.obj) : error LNK2001: 无法解析的外部符号 _IID_IWICImagingFactory
- Tensorflow api