View从创建到显示到屏幕需要经历几个过程:

measure -> layout -> draw

measure过程:计算view所占屏幕大小
layout过程:设置view在屏幕的位置
draw过程:绘制view


继承自view的控件的measure过程

view.measure(int,int)方法有什么作用?

view.measure(int,int)用于询问(或称为设置)当前view需要(想要)占用多大得空间。
简单理解为,为view申请两个int值大小的尺寸的控件

View.java

/***
* <p>
* This is called to find out how big a view should be. The parent
* supplies constraint information in the width and height parameters.
* </p>
*
* <p>
* The actual mesurement work of a view is performed in
* {@link #onMeasure(int, int)}, called by this method. Therefore, only
* {@link #onMeasure(int, int)} can and must be overriden by subclasses.
* </p>
*
*
* @param widthMeasureSpec Horizontal space requirements as imposed by the
* parent
* @param heightMeasureSpec Vertical space requirements as imposed by the
* parent
*
* @see #onMeasure(int, int)
*/
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) { // first clears the measured dimension flag
mPrivateFlags &= ~MEASURED_DIMENSION_SET; if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE);
} // measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec); // flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
throw new IllegalStateException("onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
} mPrivateFlags |= LAYOUT_REQUIRED;
} mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
}

从源码看,我们需要关注的几个方法有:
onMeasure(int,int);                 //如有需求,需重写
setMeasuredDimension(int,int);//保存结果
getDefaultSize(int,int);         //原逻辑
getSuggestMinimumHeight(); //原逻辑
getSuggestMinimumWidth();  //原逻辑

MeasureSpec类
MeasureSpec.getMode();
MeasureSpec.getSize();
MeasureSpec.UNSPECIFIED
MeasureSpec.AT_MOST
MeasureSpec.EXACTLY

回过头说,什么时候会用到view.measure(int,int)?
通常情况下,很少显式调用view.measure(int,int)方法,除非是需要根据需求变更view的大小和位置
更多调用view.measure(int,int)方法的是android框架本身,当绘制创建控件时候,android框架会调用此方法
询问view需要多大的空间。

说到这,可以知道两个参数widthMeasureSpec,heightMeasureSpec的作用了。
measure方法中的两个参数是父类传递过来给当前view的一个建议值,即想把当前view的尺寸
设置为宽widthMeasureSpec,高heightMeasureSpec

回到View源码中可以看到,在调用measure(int,int)之后,如果与old值不相等则会回调view的onMeasure(int,int)方法
进行具体实质性的view大小的计算.
(所以,如果你想对自己的view进行一些定制,则需要重写view的onMeasure(int,int)方法,把定制代码写在此方法中)
(注意:从measure源码可以得知,重写onMeasure方法时候记得要调用setMeasuredDimension(int,int),否则在measure中会抛出IllegalStateException异常)

    /***
* <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));
}

其中涉及到三个方法:
setMeasuredDimension(int,int)
getDefaultSize(int,int)            //原实现
getSuggestedMinimumHeight();//原实现
getSuggestedMinimumWidth(); //原实现

setMeasuredDimension:

    /***
* <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));
}

getDefaultSize:

    /***
* Utility to return a default size. Uses the supplied size if the
* MeasureSpec imposed no contraints. Will get larger if allowed
* by the MeasureSpec.
*
* @param size Default size for this view
* @param measureSpec Constraints imposed by the parent
* @return The size this view should be.
*/
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}

getSuggestedMinimumHeight:

    /***
* Returns the suggested minimum height that the view should use. This
* returns the maximum of the view's minimum height
* and the background's minimum height
* ({@link android.graphics.drawable.Drawable#getMinimumHeight()}).
* <p>
* When being used in {@link #onMeasure(int, int)}, the caller should still
* ensure the returned height is within the requirements of the parent.
*
* @return The suggested minimum height of the view.
*/
protected int getSuggestedMinimumHeight() {
int suggestedMinHeight = mMinHeight; if (mBGDrawable != null) {
final int bgMinHeight = mBGDrawable.getMinimumHeight();
if (suggestedMinHeight < bgMinHeight) {
suggestedMinHeight = bgMinHeight;
}
} return suggestedMinHeight;
}

getSuggestedMinimumWidth:

    /***
* Returns the suggested minimum width that the view should use. This
* returns the maximum of the view's minimum width)
* and the background's minimum width
* ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
* <p>
* When being used in {@link #onMeasure(int, int)}, the caller should still
* ensure the returned width is within the requirements of the parent.
*
* @return The suggested minimum width of the view.
*/
protected int getSuggestedMinimumWidth() {
int suggestedMinWidth = mMinWidth; if (mBGDrawable != null) {
final int bgMinWidth = mBGDrawable.getMinimumWidth();
if (suggestedMinWidth < bgMinWidth) {
suggestedMinWidth = bgMinWidth;
}
} return suggestedMinWidth;
}

setMeasuredDimension(int,int)方法
保存了传入的建议尺寸

getDefaultSize(int,int)方法
获取一个默认值

getSuggestedMinimumHeight()方法
获取此控件的最小可用值(如果设置了android:minHeight

getSuggestedMinimumWidth()方法
获取此控件的最小可用值(如果设置了android:minWidth

View源码中可以看到,关键在于getDefaultSize(int,int)方法它,返回最终传递给setMeasuredDimension(int,int)方法的数据,view就用这两个int值最为view的宽高了

getDefaultSize(int,int)中关键在于MeasureSpec类

MeasureSpec类封装了父ivew传递给子view的布局要求,每个MeasureSpc实例代表宽度和高度要求

MeasureSpec.getMode(int)方法

将根据传入的int测量值获取一个对应的模式:
MeasureSpec.UNSPECIFIED:未指定.即父元素对子元素无任何限制
MeasureSpec.EXACTLY:表示确定大小.即父元素决定子元素的确切大小
MeasureSpec.AT_MOST:至多.即子元素最多能到达的大小
(这三个模式与match_parent,wrap_parent的关系十分紧密,之后详细研究)

MeasureSpec.getSize(int)
根据传入的int测量值获取一个int值表达控件的大小

MeasureSpec.makeMeasureSpec(int size,int mode)方法
根据提供的大小值和模式,创建一个测量值

android原实现中getDefaultSize(int,int)可以看到
如果模式为MeasureSpec.UNSPECIFIED,最终大小就是我们申请的大小,如果模式为
MeasureSpec.AT_MOST或者case MeasureSpec.EXACTLY,则最终结果则为MeasureSpec.getSize(measureSpec)的结果


好了,到此android中view的默认实现过程基本结束,做一个简单总结:

1.父类调用view.measure(int,int),传入测量值,建议值
2.子view回调onMeasure(int,int),计算得到最终view的尺寸大小
3.测量过程结束,进行layout过程

所以,如果你自定义一个控件时,对其尺寸有特殊要求,则重写view的onMeasure(int.int)方法对尺寸进行定制即可
(算完之后记得调用setMeasuredDimension(int,int)方法保存计算结果和设置标志,否则抛出异常)


最后:
以上都是个人理解,难免错漏,如需深入研究请转至大神博客:

http://blog.csdn.net/qinjuning/article/details/8074262

[Android学习笔记]View的measure过程学习的更多相关文章

  1. [Android学习笔记]View的draw过程学习

    View从创建到显示到屏幕需要经历几个过程: measure -> layout -> draw measure过程:计算view所占屏幕大小layout过程:设置view在屏幕的位置dr ...

  2. [Android学习笔记]view的layout过程学习

    View从创建到显示到屏幕需要经历几个过程: measure -> layout -> draw measure过程:计算view所占屏幕大小layout过程:设置view在屏幕的位置dr ...

  3. Android学习笔记View的工作原理

    自定义View,也可以称为自定义控件,通过自定义View可以使得控件实现各种定制的效果. 实现自定义View,需要掌握View的底层工作原理,比如View的测量过程.布局流程以及绘制流程,除此之外,还 ...

  4. openstack学习笔记一 虚拟机启动过程代码跟踪

    openstack学习笔记一 虚拟机启动过程代码跟踪 本文主要通过对虚拟机创建过程的代码跟踪.观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程. 当从horizon界面发 ...

  5. 【Android - 自定义View】之View的measure过程解析

    measure(测量)过程是View的工作流程中最开始.最核心的过程,在这个过程中负责确定View的测量宽/高. 对于View和ViewGroup,measure过程有不同的执行方法:如果目标是一个原 ...

  6. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  7. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  8. 20145230《java学习笔记》第七周学习总结

    20145230 <Java程序设计>第7周学习总结 教材学习内容 Lambda语法概览 我们在许多地方都会有按字符串长度排序的需求,如果在同一个方法内,我们可以使用一个byName局部变 ...

  9. 【学习笔记】JavaScript的基础学习

    [学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...

随机推荐

  1. [Boost]boost的时间和日期处理-(2)时间的操作

    <开篇> 本篇紧接着boost上篇叙述Boost::DateTime的时间处理.在C++中,常见的时间有time_t, FILETIME和tm,而boost中用ptime. 构造ptime ...

  2. Creating Spatial Indexes(mysql 创建空间索引 The used table type doesn't support SPATIAL indexes)

    For MyISAM tables, MySQL can create spatial indexes using syntax similar to that for creating regula ...

  3. Windows的TCP协议参数

    注册表编辑器:regedit 表项:HKEY_LOCAL_MACHINE\SYSTEM\CurentControlSet\Services\Tcpip\Parameters 窗口扩大因子 & ...

  4. TCP连接状态具体解释

    tcp状态: LISTEN:侦听来自远方的TCPport的连接请求 SYN-SENT:再发送连接请求后等待匹配的连接请求 SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认 ...

  5. SQL Server 存储过程、触发器、游标

    存储过程 1.存储过程是事先编好的.存储在数据库中的程序,这些程序用来完成对数据库的指定操作. 2.系统存储过程: SQL Server本身提供了一些存储过程,用于管理有关数据库和用户的信息. 用户存 ...

  6. Join的实现步骤 以及连接的概念

    Join的实现步骤  以及连接的概念 我们常说连接有三种,即 交叉连接.内连接.外连接,这三者的概念很容易模糊,现在我们先放下概念,搞清楚完整连接实现的步骤: 一个完整的连接有三个步骤:.做笛卡儿积: ...

  7. ssh登录的时候,根本不给输入密码的机会,直接拒绝,是因为BatchMode的设置

    BatchMode no“BatchMode”如果设为“yes”,passphrase/password(交互式输入口令)的提示将被禁止.当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分 ...

  8. 使用ItextSharp产PDF完整操作

    原文 使用ItextSharp产PDF完整操作 记得上回有写到用C#操作Excel(.net 4.0) 很多朋友说推荐用NPOI,的确,用微软自带的操作execl会有很大的问题.客户的主机不愿意安装e ...

  9. Tomcat 7最大并发连接数的正确修改方法(转)

    几乎所有的中文网页都介绍,要修改Tomcat的默认最大并发连接数,应该进行如下设置(实际上这些步骤是错误的): -------------------------------------------- ...

  10. XSS漏洞解决方案之一:过滤器

    一:web.xml文件 <!-- 解决xss漏洞 --> <filter> <filter-name>xssFilter</filter-name>   ...