android 自定义view-onMeasure
2016-01-21 11:11
561 查看
当进行自定义view时我们首先需要知道这个view的大小,在android中是通过onMeasure来进行测量的,在看《android群英传》后记录学习过程。
在自定义view时我们需要重写onMeasure方法进行view的测量。
如何测量:
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方法。
下面通过一个具体的实例进行加深理解:
我们自定义view,没有重写onMeasure方法,此时布局文件写的宽和高为wrap_content,此时系统不知道该绘制多大的,所致默认会填充整个父布局,我们重写onMeasure方法就是让系统能够知道view的大小从而能够绘制出来。
当我们指定了控件的具体大小或者为match_parent时系统此刻就知道该绘制多大的了。
布局文件activity_main.xml
重写onMeasure方法获取view的大小:
若我们没有指定其大小,而是使用wrap_content时则会显示默认的大小200px和400dpx
布局activity_main.xml
通过以上实例我们就可以加深对onMeasure方法的理解。
在自定义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方法的理解。
相关文章推荐
- Android Studio安装插件
- 如何分析解决Android ANR
- 强烈推荐android studio用的几个插件
- android sdk 更新 不翻墙
- Android Tab(TabLayout+Fragment)
- android程序获取手机imei方法
- 【Android】直接利用View创建Dialog
- android界开发如何禁止密码输入框复制粘贴
- Android 四大组件详解(二) Service
- Android textView字间距自定义LetterSpacingTextView
- Android之SharedPreferences详解
- Android官方课程总结笔记【多媒体之音频管理】
- 关于android6.0不能使用BLE
- Android抖动的输入框
- 在Android源码目录用javadoc生成API html文档
- Android自定义View——自定义样式
- Android 应用启动速度优化
- Android沉浸式状态栏SystemBarTint的使用方法
- Android Studio 关于so文件导入的若干方案
- Android 自定义对话框(控制大小、位置)