Android中View的MeasureSpec以及Measure的过程
2017-08-13 15:29
387 查看
一、了解View的MeasureSpec
MeasureSpec从字面上的意思来是测量说明书,实际上载View的Measure过程中,它的确起到了非常重要的作用。MeasureSpec是一个32位的Integer值,它由两个部分组成分别是SpecMode和SpecSize,即测量模式和该模式下的尺寸。
通过makeMeasureSpec(SpecSize, SpecMode)可以得到MeasureSpec
通过getMode(MeasureSpec)和 getSize(MeasureSpec)解包可以获得该MeasureSpec对应的mode和size。
SpecMode有三个具体的模式:
1.UNSPECIFIED(对应获取不到View的LayoutParams的情况)
2.EXACTLY(对应View的LayoutParams为match_parent和设置了具体数值的情况)
3.AT_MOST(对应View的LayoutParams为wrap_content的情况)
二、DecorView的MeasureSpec
一般情况下来说,View的MeasureSpec是由父容器的约束和自身的LayoutParams共同决定的,但是DecorView是Android中最顶层的View它是没有父容器的,那么约束它的工作自然而然就交给了Window,它的MeasureSpec是通过getRootMeasureSpec()方法获取到的,源码如下:/** * @param windowSize: 即Window的大小 * @param rootDimension:即DecorView的LayoutParams */ private static int getRootMeasureSpec(int windowSize, int rootDimension) { int measureSpec; switch(rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTILY); break; case ViewGroup.LayoutParams.WRAP_CONTENT: measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break; default: measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTILY); break; } }
获取到DecorView的MeasureSpec后会执行performMeasure(childWidthMeasureSpec, childHeightMeasureSpce)该方法发起DecorView的measure过程
三、View的MeasureSpec
除了DecorView比较特殊之外,其他View的MeasureSpec都是通过其父容器构建好,传递到其onMeasure()方法中的。接下来就来看看View的MeasureSpec是如何在其父容器中构建的。protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams)child.getLayoutParams(); //getChildMe 4000 asureSpec()传入三个参数 //第一个是该ViewGroup的MeasureSpec //第二个是该ViewGroup的childView不可用的空间 //第三个为childView的LayoutParams final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeighteasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + widthUsed, lp.width); child.measure(childWidthMeasureSpec, childHeighteasureSpec); }
由上面的代码可知,View的MeasureSpec是在它的父容器中measureChildWithMargins()方法通过getChildMeasureSpec()获取到的
getChildMeasureSpec()该方法会根据当前ViewGroup的MeasureSpec的SpecMode与 View的LayoutParams共同决定子View的SpecMode和SpecSize,最终通过makeMeasureSpec()将其打包成子View的MeasureSpec。
View的MeasureSpec生成好之后会调用View的measure方法发起子View的Measure过程
四、View的Measure过程
View的measure方法会去调用其自身的onMeasure方法,下面看看原生View的onMeasure源码:protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //设置View测量的尺寸 //getDefaultSize()为获取系统默认的尺寸,其两个参数分别为Size,和MeasureSpec setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
getSuggestedMinimumXXX()类型的方法是判断当前View是否设置了背景图,若设置了背景图则返回设置的尺寸和背景图中的最大值
接下来分析getDefaultSize方法,源码如下:
public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch(specMode) { //如果测量模式为不确定时,result即为getSuggestedMinimumXXX() case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: //如果测量模式为精确值时,result即为measureSpec重的specSize case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
由上述源码可知我们原生View对于AT_MOST类型的Mode是没有做任何处理的,也没有break,所以会继续往下执行也就是说wrap_content的效果与match_parent是一致的,所以我们想要完成wrap_cotent的效果,需要重写View的onMeasure方法自己去实现(TextView、ImageView均做了相应的处理)。
五、ViewGroup的Measure过程
ViewGroup是一个抽象类继承自View,它没有重写View的onMeasure方法,将Measure的过程交给具体的实现者,但是它提供了measureChildXXX的方法,该方法会循环遍历ViewGroup中的childView,获取其MeasureSpec后并调用childView的measure方法, 当所有的childView测量结束后, 再具体的执行其Measure自身的操作相关文章推荐
- Android中measure过程、view绘制原理和MeasureSpec介绍及使用详解
- Android中自定义View的onMeasure以及MeasureSpec使用
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
- Android中View的绘制过程 onMeasure方法简述
- Android中View和ViewGroup的measure和layout过程分析
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例
- Android学习Scroller(五)——详解Scroller调用过程以及View的重绘
- Android开发之View重写相关API-onLayout,onMeasure,MeasureSpec
- Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析
- android绘制view的过程之一---------计算view大小(measure)
- Android中View的绘制过程 onMeasure方法
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- android绘制view的过程之一---------计算view大小(measure)(转)
- Android View深入学习(一),View的测量(Measure)过程
- Android 自定义View 之测量过程(onMeasure)
- Android View的Measure过程(一)
- Android中view的测量过程中,很重要的也很难理解的一个东西MeasureSpec
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析
- Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析