view measure详解
源码路径 frameworks\base\core\java\android\view\View.java
源码中国链接:http://www.oschina.net/code/explore/android-2.2-froyo/android/view/View.java
[java] view plain copy- publicfinalvoidmeasure(intwidthMeasureSpec,intheightMeasureSpec){
- if((mPrivateFlags&FORCE_LAYOUT)==FORCE_LAYOUT||
- widthMeasureSpec!=mOldWidthMeasureSpec||
- heightMeasureSpec!=mOldHeightMeasureSpec){
- //firstclearsthemeasureddimensionflag
- mPrivateFlags&=~MEASURED_DIMENSION_SET;
- if(ViewDebug.TRACE_HIERARCHY){
- ViewDebug.trace(this,ViewDebug.HierarchyTraceType.ON_MEASURE);
- }
- //measureourselves,thisshouldsetthemeasureddimensionflagback
- onMeasure(widthMeasureSpec,heightMeasureSpec);
- //flagnotset,setMeasuredDimension()wasnotinvoked,weraise
- //anexceptiontowarnthedeveloper
- if((mPrivateFlags&MEASURED_DIMENSION_SET)!=MEASURED_DIMENSION_SET){
- thrownewIllegalStateException("onMeasure()didnotsetthe"
- +"measureddimensionbycalling"
- +"setMeasuredDimension()");
- }
- mPrivateFlags|=LAYOUT_REQUIRED;
- }
- mOldWidthMeasureSpec=widthMeasureSpec;
- mOldHeightMeasureSpec=heightMeasureSpec;
- }
(mPrivateFlags这个还没研究,先跳过了)
1.检查传入的widthMeasureSpec和heightMeasureSpec是否与当前的值是一样的,不一样的话,调用onMeasure函数,并设置mPrivateFlags。
2.保存新值到mOldWidthMeasureSpec和mOldHeightMeasureSpec。这两个变量不用深究了,没有其他地方用到,就只是在这个函数中用来比较值用的。
3.这里判断符合条件后会抛出一个IllegalStateException的异常,它的提示信息很清楚,告诉我们要调用setMeasuredDimension()方法。但到底是怎么回事呢?这是在你需要重写onMeasure函数时需要注意的。
先来看看默认的View的onMeasure函数吧:
[java] view plain copy- protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec));
- }
继续来看setMeasuredDimension:
[java] view plain copy- protectedfinalvoidsetMeasuredDimension(intmeasuredWidth,intmeasuredHeight){
- mMeasuredWidth=measuredWidth;
- mMeasuredHeight=measuredHeight;
- mPrivateFlags|=MEASURED_DIMENSION_SET;
- }
- publicstaticintgetDefaultSize(intsize,intmeasureSpec){
- intresult=size;
- intspecMode=MeasureSpec.getMode(measureSpec);
- intspecSize=MeasureSpec.getSize(measureSpec);
- switch(specMode){
- caseMeasureSpec.UNSPECIFIED:
- result=size;
- break;
- caseMeasureSpec.AT_MOST:
- caseMeasureSpec.EXACTLY:
- result=specSize;
- break;
- }
- returnresult;
- }
看到了一个MeasureSpec,看来主要工作是在这里,必须得进去看看了。
[java] view plain copy- publicstaticclassMeasureSpec{
- privatestaticfinalintMODE_SHIFT=30;
- privatestaticfinalintMODE_MASK=0x3<<MODE_SHIFT;
- publicstaticfinalintUNSPECIFIED=0<<MODE_SHIFT;
- publicstaticfinalintEXACTLY=1<<MODE_SHIFT;
- publicstaticfinalintAT_MOST=2<<MODE_SHIFT;
- publicstaticintmakeMeasureSpec(intsize,intmode){
- returnsize+mode;
- }
- publicstaticintgetMode(intmeasureSpec){
- return(measureSpec&MODE_MASK);
- }
- publicstaticintgetSize(intmeasureSpec){
- return(measureSpec&~MODE_MASK);
- }
- }
类不大,就都贴出来了,为了精简篇幅,去掉了注释和toString函数。
这里MODE_MASK二进制是11000(一共30个0)00,也就是最高2位标识mode,其余位标识size。
接下来回到getDefaultSize函数
通过这个类的方法从参数measureSpec中提取出了specMode和specSize。 specMode的作用在下面的switch语句中可以看出来。
[java] view plain copy- caseMeasureSpec.UNSPECIFIED:
- result=size;
- break;
[java] view plain copy
- caseMeasureSpec.AT_MOST:
- caseMeasureSpec.EXACTLY:
- result=specSize;
- break;
简单示例:
OK,现在应该理解了吧,下面是一个调用measure方法的示例:
[java] view plain copy
- mTextView.measure(MeasureSpec.EXACTLY+mTextView.getWidth(),MeasureSpec.EXACTLY);
- mTextView.layout(0,0,mTextView.getMeasuredWidth(),mTextView.getMeasuredHeight());
当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。按示例调用layout函数后,View的大小将会变成你想要设置成的大小。
另外关于layout,包括整个布局流程,我将要写另一篇博文介绍。因此在这里就不再赘述了。
更多相关文章
- C语言函数以及函数的使用
- android 调用draw(canvas) 函数自动退出
- 解析ANDROID ps命令执行后各项参数的含义
- Xposed框架之函数Hook学习
- Flutter下载更新App的方法示例
- Android之——多线程断点续传下载示例
- Android/iOS内嵌Unity开发示例
- 布局中文件中【控件间距参数详解以及单位选择】