android 自定义view-onMeasure
来源:互联网 发布:java角色权限 编辑:程序博客网 时间:2024/05/16 14:40
当进行自定义view时我们首先需要知道这个view的大小,在android中是通过onMeasure来进行测量的,在看《android群英传》后记录学习过程。
在自定义view时我们需要重写onMeasure方法进行view的测量。
/** * <p> * Measure the view and its content to determine the measured width and the * measured height. This method is invoked by {@link #measure(int, int)} and * should be overriden by subclasses to provide accurate and efficient * measurement of their contents. * </p> * * <p> * <strong>CONTRACT:</strong> When overriding this method, you * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the * measured width and height of this view. Failure to do so will trigger an * <code>IllegalStateException</code>, thrown by * {@link #measure(int, int)}. Calling the superclass' * {@link #onMeasure(int, int)} is a valid use. * </p> * * <p> * The base class implementation of measure defaults to the background size, * unless a larger size is allowed by the MeasureSpec. Subclasses should * override {@link #onMeasure(int, int)} to provide better measurements of * their content. * </p> * * <p> * If this method is overridden, it is the subclass's responsibility to make * sure the measured height and width are at least the view's minimum height * and width ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()}). * </p> * * @param widthMeasureSpec horizontal space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * @param heightMeasureSpec vertical space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * * @see #getMeasuredWidth() * @see #getMeasuredHeight() * @see #setMeasuredDimension(int, int) * @see #getSuggestedMinimumHeight() * @see #getSuggestedMinimumWidth() * @see android.view.View.MeasureSpec#getMode(int) * @see android.view.View.MeasureSpec#getSize(int) */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }以上是父类view的onMeasure方法实现,我们可以看到系统会最终调用setMeasureDimension(width,height)方法将测量后的宽和高设置进去,完成view的测量,所以我们重写view的时候需要把测量的view的宽和高传到setMeasureDimension里面去完成测量。
如何测量:
android中提供给我们一个MeasureSpec类来完成view的测量。MeasureSpec是一个32位的int 值,其中高2位为测量的模式,低2位为测量的大小。测量的模式主要分为EXACTLY、AT_MOST、UNSPECIFIED三种值。
- EXACTLY
准确精度值模式,当设置控件的宽和高为具体的值是如:100dp等就是用的这个值,或者match_parent
- AT_MOST
当设置控件的宽和高为wrap_content时,则其大小为控件的内容变化而变化。
- UNSPECIFIED
不指定测量大小模式,view想多大就有多大。
view的默认的模式就是第一种精确模式,所以自定义view时不重写onMeasure方法就是使用EXACTLY模式,即支持view的具体值或者match_parent属性,而如果view的宽和高指定为wrap_content时就必须重写onMeasure方法。
下面通过一个具体的实例进行加深理解:
public class TestCustomeView2 extends View { public TestCustomeView2(Context context) { super(context); } public TestCustomeView2(Context context, AttributeSet attrs) { super(context, attrs); } public TestCustomeView2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); }}布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.customview.widget.TestCustomeView2 android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#fffaaa"/></RelativeLayout>
我们自定义view,没有重写onMeasure方法,此时布局文件写的宽和高为wrap_content,此时系统不知道该绘制多大的,所致默认会填充整个父布局,我们重写onMeasure方法就是让系统能够知道view的大小从而能够绘制出来。
当我们指定了控件的具体大小或者为match_parent时系统此刻就知道该绘制多大的了。
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.customview.widget.TestCustomeView2 android:layout_width="300dp" android:layout_height="200dp" android:background="#fffaaa"/></RelativeLayout>
重写onMeasure方法获取view的大小:
public class TestCustomeView extends View { public TestCustomeView(Context context) { super(context); } public TestCustomeView(Context context, AttributeSet attrs) { super(context, attrs); } public TestCustomeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } /** * 获取view的高度,当没有指定大小时给予默认的高为400px * @param measureSpec * @return */ private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); //如果布局控件指定大小则返回其大小值,否则返回默认的值 if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 400; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * 获取view的宽度,当没有指定大小时给予默认的高为200px * @param measureSpec * @return */ private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); //如果布局控件指定大小则返回其大小值,否则返回默认的值 if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = 200; if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }}布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.customview.widget.TestCustomeView android:layout_width="400dp" android:layout_height="200dp" android:background="#fffaaa"/></RelativeLayout>
若我们没有指定其大小,而是使用wrap_content时则会显示默认的大小200px和400dpx
布局activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.customview.widget.TestCustomeView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#fffaaa"/></RelativeLayout>
通过以上实例我们就可以加深对onMeasure方法的理解。
1 0
- Android自定义View onMeasure
- android 自定义view-onMeasure
- android 自定义view onMeasure()
- android 自定义view之onMeasure
- Android 自定义View onMeasure理解
- android 自定义view中onMeasure()
- Android自定义View-onMeasure介绍
- android 自定义view中onMeasure()理解
- android 自定义view中onMeasure()理解
- Android 自定义view 和 onMeasure方法介绍
- Android 自定义View 中的OnMeasure的用法
- android 自定义view中onMeasure()理解
- Android 自定义view 和 onMeasure方法介绍
- android自定义View中onMeasure的使用
- Android 自定义View 中的OnMeasure的用法
- Android自定义View基础之onMeasure详解
- Android 自定义View总结 —— onMeasure()
- Android 自定义View 中的OnMeasure的用法
- 魔兽争霸3下载
- 网页布局与盒子模型
- Android知识点:Looper、Message、Handler之间的关系
- 我的 Xcode 插件单
- if语句
- android 自定义view-onMeasure
- Inno Setup 安装时每个section调用顺序
- Android学习历程5-Android内存泄漏总结
- Android Studio的插件
- 桶排序Bucket sort
- 网站PC前端图片加载优化---jQuery lazyload
- 分治法算法——归并排序
- 【费用流模型】BZOJ2668 UVA1317 UVA1486 UVA1104
- bzoj3661: Hungry Rabbit