MeasureSpec 资料汇总

50 篇文章 0 订阅

来源:http://blog.csdn.net/whyrjj3/article/details/7927585


在自定义ViewViewGroup的时候,我们经常会遇到int型的MeasureSpec来表示一个组件的大小,这个变量里面不仅有组件的尺寸大小,还有大小的模式。


这个大小的模式,有点难以理解。在系统中组件的大小模式有三种:


1.精确模式

在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。


2.最大模式

这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。


3.未指定模式

这个就是说,当前组件,可以随便用空间,不受限制。


可能有很多人想不通,一个int型整数怎么可以表示两个东西(大小模式和大小的值),一个int类型我们知道有32位。而模式有三种,要表示三种状态,至少得2位二进制位。于是系统采用了最高的2位表示模式。如图:


最高两位是00的时候表示"未指定模式"。即MeasureSpec.UNSPECIFIED

最高两位是01的时候表示"'精确模式"。即MeasureSpec.EXACTLY

最高两位是11的时候表示"最大模式"。即MeasureSpec.AT_MOST



很多人一遇到位操作头就大了,为了操作简便,于是系统给我提供了一个MeasureSpec工具类。

这个工具类有四个方法和三个常量(上面所示)供我们使用:



//这个是由我们给出的尺寸大小和模式生成一个包含这两个信息的int变量,这里这个模式这个参数,传三个常量中的一个。

public static int makeMeasureSpec(int size, int mode)



//这个是得到这个变量中表示的模式信息,将得到的值与三个常量进行比较。

public static int getMode(int measureSpec)



//这个是得到这个变量中表示的尺寸大小的值。

public static int getSize(int measureSpec)



//把这个变量里面的模式和大小组成字符串返回来,方便打日志

 public static String toString(int measureSpec)



来源:http://www.cnblogs.com/xirihanlin/archive/2009/07/23/1529238.html


除非你总是需要一个100×100像素的控件,否则,你必须要重写onMeasure

 

onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——

widthMeasureSpec和heightMeasureSpec。它们指明控件可获得的空间以及关于这个空间描述的元数据。

 

比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。

 

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

 

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int measuredHeight = measureHeight(heightMeasureSpec);

int measuredWidth = measureWidth(widthMeasureSpec);

setMeasuredDimension(measuredHeight, measuredWidth);

}

 

private int measureHeight(int measureSpec) {

// Return measured widget height.

}

 

private int measureWidth(int measureSpec) {

// Return measured widget width.

}

 

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

 

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

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

 

当以EXACT方式标记测量尺寸,父元素会坚持在一个指定的精确尺寸区域放置View。在父元素问子元素要多大空间时,AT_MOST指示者会说给我最大的范围。在很多情况下,你得到的值都是相同的。

 

在两种情况下,你必须绝对的处理这些限制。在一些情况下,它可能会返回超出这些限制的尺寸,在这种情况下,你可以让父元素选择如何对待超出的View,使用裁剪还是滚动等技术。

 

接下来的框架代码给出了处理View测量的典型实现:

 

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int measuredHeight = measureHeight(heightMeasureSpec);

int measuredWidth = measureWidth(widthMeasureSpec);

setMeasuredDimension(measuredHeight, measuredWidth);

}

 

private int measureHeight(int measureSpec) {

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

// Default size if no limits are specified.

int result = 500;

if (specMode == MeasureSpec.AT_MOST)

{

// Calculate the ideal size of your

// control within this maximum size.

// If your control fills the available

// space return the outer bound.

result = specSize;

}

else if (specMode == MeasureSpec.EXACTLY)

{

// If your control can fit within these bounds return that value.

result = specSize;

}

return result;

}

 

private int measureWidth(int measureSpec) {

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

// Default size if no limits are specified.

int result = 500;

if (specMode == MeasureSpec.AT_MOST)

{

// Calculate the ideal size of your control

// within this maximum size.

// If your control fills the available space

// return the outer bound.

result = specSize;

}

else if (specMode == MeasureSpec.EXACTLY)

{

// If your control can fit within these bounds return that value.

result = specSize;

}

return result;

}


来源:http://blog.csdn.net/startfromweb/article/details/7799427


 一个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)

[java]  view plain copy
  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方法,实际上这个方法很简单:

[java]  view plain copy
  1. public static int makeMeasureSpec(int size, int mode) {  
  2.         return size + mode;  
  3. }  
这样大家不难理解size跟measureSpec区别了。看看它的使用吧,ListView.measureItem(View child)

[java]  view plain copy
  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.    
  9.          int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,  
  10.                  mListPadding.left + mListPadding.right, p.width);  
  11.          int lpHeight = p.height;  
  12.          int childHeightSpec;  
  13.          if (lpHeight > 0) {  
  14.              childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);  
  15.          } else {  
  16.              childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);  
  17.          }  
  18.          child.measure(childWidthSpec, childHeightSpec);  
  19.      }  

measureSpec方法通常在ViewGroup中用到,它可以根据模式(MeasureSpec里面的三个)可以调节子元素的大小。

  注意,使用EXACTLY和AT_MOST通常是一样的效果,如果你要区别他们,那么你就要使用上面的函数View.resolveSize(int size,int measureSpec)返回一个size值,然后使用你的view调用setMeasuredDimension(int,int)函数。


[java]  view plain copy
  1. protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {  
  2.  mMeasuredWidth = measuredWidth;  
  3. mMeasuredHeight = measuredHeight;  
  4.   mPrivateFlags |= MEASURED_DIMENSION_SET;  

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值