Android中自定义View的onMeasure以及MeasureSpec使用
来源:互联网 发布:生刷枪软件下载 编辑:程序博客网 时间:2024/05/20 11:49
一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定该控件在屏幕上的大小。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ///your code }
onMeasure传入的两个参数是由上一层控件传入的大小,有多种情况,重写该方法时需要对计算控件的实际大小,然后调用setMeasuredDimension(int, int)设置实际大小。
onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。我们需要通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
/** * Measure specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */ public static final int UNSPECIFIED = 0 << MODE_SHIFT; /** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ public static final int EXACTLY = 1 << MODE_SHIFT; /** * Measure specification mode: The child can be as large as it wants up * to the specified size. */ public static final int AT_MOST = 2 << MODE_SHIFT;
MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为android:layout_width="fill_parent",都是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
————也就是说此时通过 MeasureSpec.getSize(widthMeasureSpec)获取的size只是给出了允许的最大尺寸。
MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
因此,在重写onMeasure方法时要根据模式不同进行尺寸计算。下面代码就是一种比较典型的方式:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == HORIZONTAL) { setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); } else { setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); } } /** * Determines the width of this view * * @param measureSpec * A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureLong(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); Log.d("TAG", "measureLong specSize="+specSize); //此处由于android:layout_height="fill_parent"属性 //那么,specMode值为MeasureSpec.EXACTLY, //specSize计算出的值为精确值,可以直接使用 if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { Log.d("TAG", "measureLong MeasureSpec.EXACTLY"); //We were told how big to be result = specSize; } else { Log.d("TAG", "measureLong other"); //Calculate the width according the views count final int count = mViewPager.getAdapter().getCount(); result = (int)(getPaddingLeft() + getPaddingRight() + (count * 2 * mRadius) + (count - 1) * mRadius + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * Determines the height of this view * * @param measureSpec * A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */ private int measureShort(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); Log.d("TAG", "measureShort specMode="+specMode); Log.d("TAG", "measureShort specSize="+specSize); //此处由于android:layout_height="wrap_content"属性 //那么,specMode值为MeasureSpec.AT_MOST, //specSize计算出的值为控件允许的最大值,记住,仅仅是最大允许的值,而非实际值。 if (specMode == MeasureSpec.EXACTLY) { Log.d("TAG", "measureShort MeasureSpec.EXACTLY"); //We were told how big to be result = specSize; } else { Log.d("TAG", "measureShort other"); //Measure the height result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }
该自定义View在xml中的布局如下:
<com.viewpagerindicator.CirclePageIndicator android:id="@+id/indicator" android:padding="10dip" android:layout_height="wrap_content" android:layout_width="fill_parent" />
- Android中自定义View的onMeasure以及MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android中自定义View的MeasureSpec使用
- Android自定义View中MeasureSpec的使用
- bootstrap 学习笔记 - 4 (按钮 + 图片 + 辅助类)
- Android ListView功能扩展,实现高性能的瀑布流布局
- 简单的横向ListView实现(version 4.0)
- <picture>-浏览器内置的响应式标签(翻译)
- Linux 内核--总线设备驱动模型(字符/块/网络设备 && platform设备)
- Android中自定义View的onMeasure以及MeasureSpec使用
- mac osx安装groovy
- java四舍五入保留两位小数方法整理
- OC第八天
- Android Context 上下文 你必须知道的一切
- Rename column SQL Server 2008(修改字段名)
- list转换json
- 为什么object.onkeyup=function(){}函数无法执行?
- leetcode第137题-Single Number II