View 中 onMeasure

今天学习android自定义组件:docs/guide/topics/ui/custom-components.html

其中有两个对布局界面影响很的方法,onDraw(),和onMeasure().

onDraw()比较好理解.onMeasure()就比较难理解一些,也更复杂些 ,引用文档中的说法就是:

实现onMeasure()方法基本需要完成下面三个方面的事情(最终结果是你自己写相应代码得出测量值并调用view的一个方法进行设置,告诉给你的view安排位置大小的父容器你要多大的空间.):

1.传递进来的参数widthMeasureSpec和heightMeasureSpec是你对你应该得出来的测量值的限制.

2. 你在onMeasure计算出来设置的width和height将被用来渲染组件.应当尽量在传递进来的width和height 声明之间.

虽然你也可以选择你设置的尺寸超过传递进来的声明.但是这样的话,父容器可以选择,如clipping,scrolling,或者抛出异常,或者(也许是用新的声明参数)再次调用onMeasure()

3.一但width和height计算好了,就应该调用View.setMeasuredDimension(int width,int height)方法,否则将导致抛出异常.    

在Android提提供的一个自定义View示例中(在API demos 中的 view/LabelView)可以看到一个重写onMeasure()方法的

实例,也比较好理解.

 
  @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
 }
 
 /**
  * 高度
  * @param heightMeasureSpec
  * @return
  */
 private int measureHeight(int heightMeasureSpec) {
    int specMode = MeasureSpec.getMode(heightMeasureSpec);
    int specSize = MeasureSpec.getSize(heightMeasureSpec);//父的空间大小
    int h = bitmap.getHeight();  //图片的高度
    int result = 0 ;
    if (specMode == MeasureSpec.EXACTLY) {//父为 wrap_content
       result = Math.min(h, specSize);
    }else if(specMode == MeasureSpec.AT_MOST){//父为fill_parent
        result = specSize;
    } else {
        result = specSize;
       }
       return result;
 }

 

  private int measureWidth(int measureSpec) {
         int result = 0;
         int specMode = MeasureSpec.getMode(measureSpec);
         int specSize = MeasureSpec.getSize(measureSpec);
 
         if (specMode == MeasureSpec.EXACTLY) {
             // We were told how big to be
             result = specSize;
         } else {
            // Measure the text
            result = (int) mTextPaint.measureText(mText) + getPaddingLeft()+ getPaddingRight();
          if (specMode == MeasureSpec.AT_MOST) {
             // Respect AT_MOST value if that was what is called for by measureSpec
             result = Math.min(result, specSize);
           }
     }
     return result;
 }

 

直接看measureWidth()

首先看到的是参数,分别代表宽度和高度的MeasureSpec

android2.2文档中对于MeasureSpec中的说明是:

一个MeasureSpec封装了从父容器传递给子容器的布局需求.

每一个MeasureSpec代表了一个宽度,或者高度的说明.

一个MeasureSpec是一个大小跟模式的组合值.一共有三种模式.

 (1)UPSPECIFIED :父容器对于子容器没有任何限制,子容器想要多大就多大.
 
 (2) EXACTLY 父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间
 
 (3) AT_MOST 子容器可以是声明大小内的任意大小.
 
MeasureSpec是View类下的静态公开类,MeasureSpec中的值作为一个整型是为了减少对象的分配开支.此类用于

将size和mode打包或者解包为一个整型.

 
posted @ 2012-08-28 14:10  土金  阅读(239)  评论(0编辑  收藏  举报