View在屏幕上显示出来要先经过measure(计算)和layout(布局).

1、什么时候调用onMeasure方法?

当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec.

这两个参数指明控件可获得的空间以及关于这个空间描述的元数据.

更好的方法是你传递View的高度和宽度到setMeasuredDimension方法里,这样可以直接告诉父控件,需要多大地方放置子控件.

  接下来的代码片段给出了如何重写onMeasure.注意,调用的本地空方法是来计算高度和宽度的.它们会译解widthHeightSpec和heightMeasureSpec值,并计算出合适的高度和宽度值.

java代码:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. int measuredHeight = measureHeight(heightMeasureSpec);
  4. int measuredWidth = measureWidth(widthMeasureSpec);
  5. setMeasuredDimension(measuredHeight, measuredWidth);
  6. }
  7. private int measureHeight(int measureSpec) {
  8. // Return measured widget height.
  9. }
  10. private int measureWidth(int measureSpec) {
  11. // Return measured widget width.
  12. }

复制代码

边界参数——widthMeasureSpec和heightMeasureSpec ,效率的原因以整数的方式传入。在它们使用之前,首先要做的是使用MeasureSpec类的静态方法getMode和getSize来译解,如下面的片段所示:

java代码:

  1. int specMode = MeasureSpec.getMode(measureSpec);
  2. int specSize = MeasureSpec.getSize(measureSpec);

复制代码

依据specMode的值,(MeasureSpec有3种模式分别是UNSPECIFIED, EXACTLY和AT_MOST)

如果是AT_MOST,specSize 代表的是最大可获得的空间; 
       如果是EXACTLY,specSize 代表的是精确的尺寸; 
       如果是UNSPECIFIED,对于控件尺寸来说,没有任何参考意义。

2、那么这些模式和我们平时设置的layout参数fill_parent, wrap_content有什么关系呢?

经过代码测试就知道,当我们设置width或height为fill_parent时,容器在布局时调用子 view的measure方法传入的模式是EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的。

而当设置为 wrap_content时,容器传进去的是AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸。当子view的大小设置为精确值时,容器传入的是EXACTLY, 而MeasureSpec的UNSPECIFIED模式目前还没有发现在什么情况下使用。 
   
       View的onMeasure方法默认行为是当模式为UNSPECIFIED时,设置尺寸为mMinWidth(通常为0)或者背景drawable的最小尺寸,当模式为EXACTLY或者AT_MOST时,尺寸设置为传入的MeasureSpec的大小。 
   
       有个观念需要纠正的是,fill_parent应该是子view会占据剩下容器的空间,而不会覆盖前面已布局好的其他view空间,当然后面布局子 view就没有空间给分配了,所以fill_parent属性对布局顺序很重要。以前所想的是把所有容器的空间都占满了,难怪google在2.2版本里把fill_parent的名字改为match_parent.

  在两种情况下,你必须绝对的处理这些限制。在一些情况下,它可能会返回超出这些限制的尺寸,在这种情况下,你可以让父元素选择如何对待超出的View,使用裁剪还是滚动等技术。
  
       接下来的框架代码给出了处理View测量的典型实现:

java代码:

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. int measuredHeight = measureHeight(heightMeasureSpec);
  4. int measuredWidth = measureWidth(widthMeasureSpec);
  5. setMeasuredDimension(measuredHeight, measuredWidth);
  6. }
  7. private int measureHeight(int measureSpec) {
  8. int specMode = MeasureSpec.getMode(measureSpec);
  9. int specSize = MeasureSpec.getSize(measureSpec);
  10. // Default size if no limits are specified.
  11. int result = 500;
  12. if (specMode == MeasureSpec.AT_MOST){
  13. // Calculate the ideal size of your
  14. // control within this maximum size.
  15. // If your control fills the available
  16. // space return the outer bound.
  17. result = specSize;
  18. }
  19. else if (specMode == MeasureSpec.EXACTLY){
  20. // If your control can fit within these bounds return that value.
  21. result = specSize;
  22. }
  23. return result;
  24. }
  25. private int measureWidth(int measureSpec) {
  26. int specMode = MeasureSpec.getMode(measureSpec);
  27. int specSize = MeasureSpec.getSize(measureSpec);
  28. // Default size if no limits are specified.
  29. int result = 500;
  30. if (specMode == MeasureSpec.AT_MOST){
  31. // Calculate the ideal size of your control
  32. // within this maximum size.
  33. // If your control fills the available space
  34. // return the outer bound.
  35. result = specSize;
  36. }
  37. else if (specMode == MeasureSpec.EXACTLY){
  38. // If your control can fit within these bounds return that value.
  39. result = specSize;
  40. }
  41. return result;
  42. }

复制代码

一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。一个MeasureSpec由大小和模式组成。它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;AT_MOST(至多),子元素至多达到指定大小的值。

  它常用的三个函数:
  1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
  2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
  3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)

  这个类的使用呢,通常在view组件的onMeasure方法里面调用但也有少数例外,看看几个例子:

  a.首先一个我们常用到的一个有用的函数,View.resolveSize(int size,int measureSpec)

  1. public static int resolveSize(int size, int measureSpec) {
  2. int result = size;
  3. int specMode = MeasureSpec.getMode(measureSpec);
  4. int specSize =  MeasureSpec.getSize(measureSpec);
  5. switch (specMode) {
  6. case MeasureSpec.UNSPECIFIED:
  7. result = size;
  8. break;
  9. case MeasureSpec.AT_MOST:
  10. result = Math.min(size, specSize);
  11. break;
  12. case MeasureSpec.EXACTLY:
  13. result = specSize;
  14. break;
  15. }
  16. return result;
  17. }

复制代码

上面既然要用到measureSpec值,那自然表示这个函数通常是在onMeasure方法里面调用的。简单说一下,这个方法的主要作用就是根据你提供的大小和模式,返回你想要的大小值,这个里面根据传入模式的不同来做相应的处理。
  
       再看看MeasureSpec.makeMeasureSpec方法,实际上这个方法很简单:

  1. public static int makeMeasureSpec(int size, int mode) {
  2. return size + mode;
  3. }

复制代码

这样大家不难理解size跟measureSpec区别了。看看它的使用吧,ListView.measureItem(View child)

  1. private void measureItem(View child) {
  2. ViewGroup.LayoutParams p = child.getLayoutParams();
  3. if (p == null) {
  4. p = new ViewGroup.LayoutParams(
  5. ViewGroup.LayoutParams.MATCH_PARENT,
  6. ViewGroup.LayoutParams.WRAP_CONTENT);
  7. }
  8. int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
  9. mListPadding.left + mListPadding.right, p.width);
  10. int lpHeight = p.height;
  11. int childHeightSpec;
  12. if (lpHeight > 0) {
  13. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
  14. } else {
  15. childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  16. }
  17. child.measure(childWidthSpec, childHeightSpec);
  18. }

复制代码

measureSpec方法通常在ViewGroup中用到,它可以根据模式(MeasureSpec里面的三个)可以调节子元素的大小。
  
       注意,使用EXACTLY和AT_MOST通常是一样的效果,如果你要区别他们,那么你就要使用上面的函数View.resolveSize(int size,int measureSpec)返回一个size值,然后使用你的view调用setMeasuredDimension(int,int)函数。

  1. protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
  2. mMeasuredWidth = measuredWidth;
  3. mMeasuredHeight = measuredHeight;
  4. mPrivateFlags |= MEASURED_DIMENSION_SET;
  5. }

复制代码

然后你调用view.getMeasuredWidth,view.getMeasuredHeigth 返回的就是上面函数里的mMeasuredWidth,mMeasuredHeight的值。

mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。

MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件
大小已经确定的情况,都是精确尺寸。

MeasureSpec.AT_MOST 是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行 变化,此时控件尺寸
只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。

MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。

原文链接:http://www.apkbus.com/android-120965-1-1.html

Android之View.onMeasure方法的更多相关文章

  1. [转]Android View.onMeasure方法的理解

    转自:http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html Android View.onMeasure方法的理解 View在屏幕上显示出来要先经过 ...

  2. Android View.onMeasure方法的理解

    View在屏幕上显示出来要先经过measure(计算)和layout(布局).1.什么时候调用onMeasure方法? 当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方 ...

  3. [转载]Android View.onMeasure方法的理解

    2013-12-18 10:56:28 转载自http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html View在屏幕上显示出来要先经过measure( ...

  4. Android View.onMeasure方法的理解(转载)

    一下内容转载自http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html View在屏幕上显示出来要先经过measure(计算)和layout(布局).1 ...

  5. android 自定义View onMeasure中 super.onMeasure 和 setMeasuredDimension

    练习写一个自定义的view,代码是抄网上的,第一次写,没有问题,与网上的示例一样的效果, 第二次.第三次,都出现问题,但是解决了. 昨天进行第四次写再写,又出问题不一样的问题了. 首先是想加一个子包, ...

  6. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  7. Android 中View的工作原理

    Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...

  8. Android 自定义 view(四)—— onMeasure 方法理解

    前言: 前面我们已经学过<Android 自定义 view(三)-- onDraw 方法理解>,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法 推荐文章: htt ...

  9. Android中View的绘制过程 onMeasure方法简述 附有自定义View例子

    Android中View的绘制过程 onMeasure方法简述 附有自定义View例子 Android中View的绘制过程 当Activity获得焦点时,它将被要求绘制自己的布局,Android fr ...

随机推荐

  1. 《javascript高级程序设计》第八章 The Browser Object Model

    8.1 window 对象 8.1.1 全局作用域 8.1.2 窗口关系及框架 8.1.3 窗口位置 8.1.4 窗口大小 8.1.5 导航和打开窗口 8.1.6 间歇调用和超时调用 8.1.7 系统 ...

  2. Scrum项目6.0

    sprint演示 1.坚持所有的sprint都结束于演示. 团队的成果得到认可,会感觉很好. 其他人可以了解你的团队在做些什么,并得到重要反馈. 演示是一种社会活动,不同的团队可以在这里相互交流,讨论 ...

  3. JavaWeb基础:Servlet

    Servlet 基本概念 Servlet是Sun公司提出的一种用于开发动态Web资源的技术规范: Servlet是一个Java接口, 用户想要开发自定义的Servlet可以通过以下步骤: 编写实现Se ...

  4. 在ubuntu(linux)下安装vim,以及vim的常用命令

    介绍vim: vim是一种编辑器,自我感觉这东西好用,就是现在有些不太习惯 如何安装: 如果是使用redhat ,系统自带着vi和vim 如果是使用ubuntu,建议使用apt-get命令, 可以尝试 ...

  5. hdu-----(1150)Machine Schedule(最小覆盖点)

    Machine Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  6. iOS控制器瘦身-面向超类编程

    今天写这篇文章的目的,是提供一种思路,来帮助大家解决控制器非常臃肿的问题,对控制器瘦身. 滴滴 老司机要开车了 如果手边有项目,不妨打开工程看一下你的控制器代码有多少行,是不是非常多?再看一下tabl ...

  7. hdu5876 Sparse Graph(补图最短路 bfs)

    题目链接:hdu5876 Sparse Graph 详见代码.. #include<cstdio> #include<cstring> #include<algorith ...

  8. PHP可变长函数方法介绍

    1.三个重要函数 func_num_args()  返回实参个数 func_get_arg(i)    返回某个实参的值       func_get_args()        以数组的形式返回实参 ...

  9. linux apache 自动监护脚本

    1 首先安装curl yum install curl 2 编写shell vi restart_apache.sh 写入一下内容 #!/bin/bashURL="http://127.0. ...

  10. jQuery.Autocomplete实现自动完成功能(详解)

    1.jquery.autocomplete参考地址 http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/ http://do ...