View的测量
2017-12-07 17:27
288 查看
在现实生活中,如果我们要去画一个图形,就必须知道它的大小和位置。同样,Android系统在绘制View之前,也必须对View进行测量,即告诉系统该画一个多大的View。这个过程在onMeasure()方法中进行。
Android系统给我们提供了一个设计短小精悍却功能强大的类--MeasureSpec类,通过它来帮助我们测量View。MeasureSpec是一个32位的int值,其中高2位为测量模式,低30位为测量的大小,在计算中使用位运算是为了提高效率。
测量的模式可以为以下三种:
EXACTLY
即精准值模式,当我们将控件的layout_with属性或layout_height属性指定为具体数值时,比如100dp,或制定为match_parent,系统使用的是EXACTLY模式。
AT_MOST
即最大值模式,当我们将控件的layout_with属性或layout_height属性指定为wrap_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
UNSPECIFIED
这个属性比较奇怪---它不知道其大小测量模式,View想多大就多大,通常情况下绘制自定义View时才会使用。
View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式。控件可以响应你指定的具体宽高值或者是match_parent属性。而如果要让自定义控件支持wrap_content属性,那么久必须重写onMeasure()方法来指定wrap_content时的大小。
通过MeasureSpec这个类,我们就获取了View的测量模式和View想要绘制的大小。有了这些信息,我们就可以控制View最后显示的大小了。
下面看一个简单的实例,自定义一个控件,重写onMeasure()方法。
跟踪到super.onMeasure()方法可以看到,系统会最终会调用setMeasuredDimension()方法将测量后的宽高度设置进去,从而完成测量工作。所以再重写onMeasure()方法后,最终要做的工作就是把测量后的宽高度值作为参数设置给setMeasuredDimension()方法。
下面时测试的例子:
下图时分别设置宽和高为wrap_content,200dp,match_parent时的程序运行效果:
可以发现,当指定wrap_content属性时,View就获得了一个默认的200px,而不是填充父布局了。
Android系统给我们提供了一个设计短小精悍却功能强大的类--MeasureSpec类,通过它来帮助我们测量View。MeasureSpec是一个32位的int值,其中高2位为测量模式,低30位为测量的大小,在计算中使用位运算是为了提高效率。
测量的模式可以为以下三种:
EXACTLY
即精准值模式,当我们将控件的layout_with属性或layout_height属性指定为具体数值时,比如100dp,或制定为match_parent,系统使用的是EXACTLY模式。
AT_MOST
即最大值模式,当我们将控件的layout_with属性或layout_height属性指定为wrap_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
UNSPECIFIED
这个属性比较奇怪---它不知道其大小测量模式,View想多大就多大,通常情况下绘制自定义View时才会使用。
View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式。控件可以响应你指定的具体宽高值或者是match_parent属性。而如果要让自定义控件支持wrap_content属性,那么久必须重写onMeasure()方法来指定wrap_content时的大小。
通过MeasureSpec这个类,我们就获取了View的测量模式和View想要绘制的大小。有了这些信息,我们就可以控制View最后显示的大小了。
下面看一个简单的实例,自定义一个控件,重写onMeasure()方法。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); }
跟踪到super.onMeasure()方法可以看到,系统会最终会调用setMeasuredDimension()方法将测量后的宽高度设置进去,从而完成测量工作。所以再重写onMeasure()方法后,最终要做的工作就是把测量后的宽高度值作为参数设置给setMeasuredDimension()方法。
下面时测试的例子:
public class MyTextView extends android.support.v7.widget.AppCompatTextView { public MyTextView(Context context) { super(context); } public MyTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } private int measureWidth(int widthMeasureSpec){ int result = 0; int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); if(mode == MeasureSpec.EXACTLY){ result = size; } else { result = 200; if(mode == MeasureSpec.AT_MOST){ result = Math.min(result, size); } } return result; } private int measureHeight(int heightMeasureSpec){ int result = 0; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); if(mode == MeasureSpec.EXACTLY){ result = size; } else { result = 200; if(mode == MeasureSpec.AT_MOST){ result = Math.min(result, size); } } return result; } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="test.chenj.study_3_1.MainActivity"> <test.chenj.study_3_1.MyTextView android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff666666" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </LinearLayout>
下图时分别设置宽和高为wrap_content,200dp,match_parent时的程序运行效果:
可以发现,当指定wrap_content属性时,View就获得了一个默认的200px,而不是填充父布局了。
相关文章推荐
- Android视图的绘制流程(上)——View的测量
- View的测量过程学习onMeasure
- 自定义View:测量measure,布局layout,绘制draw
- Android View深入学习(一),View的测量(Measure)过程
- 简单研究Android View绘制一 测量过程
- View的测量
- View的测量
- Android 自定义View 测量控件大小onMeasure中MeasureSpec作用
- Android群英传读书笔记---View测量和绘制
- android 自定义View在弹出的软键盘之上,以及测量软键盘高度和监听软键盘状态
- Android ViewGroup中有关测量的方法
- android view的测量模式
- View测量
- android测量View的宽高
- 3.4.Android控件架构与自定义控件详解之ViewGroup的测量与绘制
- android绘制自定义view时,控件大小的测量与确定问题
- 解决测量view的宽高为零的方法
- 自定义View时,wrap_content属性对测量的影响
- 自定义viewGroup childView的测量宽度时出现偏差 http://blog.csdn.net/u011102153/article/details/52245312
- view工作流程解析之measure测量