自定义控件之onMeasure

最近一直在接触自定义控件的知识,自己就尝试着写了一个小的demo,算是对自定义知识点进行下总结

今天先来看下自定义控件需要重写的三个重要方法

看代码

package com.example.testcode;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class DrawView extends View {

    public DrawView(Context context) {
        super(context);
        Log.e("123", "drawview_1");
        // TODO Auto-generated constructor stub
    }

    public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.e("123", "drawview_3");
        // TODO Auto-generated constructor stub
    }

    public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.e("123", "drawview_2");
        // TODO Auto-generated constructor stub
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.e("123", "MeasureSpec.UNSPECIFIED==" + MeasureSpec.UNSPECIFIED);
        Log.e("123", "MeasureSpec.AT_MOST==" + MeasureSpec.AT_MOST);
        Log.e("123", "MeasureSpec.EXACTLY==" + MeasureSpec.EXACTLY);
        Log.e("123", "widthMeasureSpec===" + widthMeasureSpec);
        Log.e("123", "heightMeasureSpec===" + heightMeasureSpec);
        Log.e("123", "widthMode==" + widthMode + " widthSize===" + widthSize);
        Log.e("123", "heightMode==" + heightMode + " heightSize==="
                + heightSize);
        //这两个方法必须有一个,否则会报错
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(75, 75);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        // TODO Auto-generated method stub
        Log.e("123", "change===" + changed + " left===" + left + " top==="
                + top + " right===" + right + " bottom===" + bottom);
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        Log.e("123", "onDraw");
        super.onDraw(canvas);
    }
}

 

xml中使用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.testcode.MainActivity" >

    <com.example.testcode.DrawView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="#ff0000" />

</RelativeLayout>

 

先看下我们的打印结果

  1 09-28 22:53:26.901: E/123(17442): drawview_2
  2 09-28 22:53:26.959: E/123(17442): MeasureSpec.UNSPECIFIED==0
  3 09-28 22:53:26.959: E/123(17442): MeasureSpec.AT_MOST==-2147483648
  4 09-28 22:53:26.959: E/123(17442): MeasureSpec.EXACTLY==1073741824
  5 09-28 22:53:26.959: E/123(17442): widthMeasureSpec===1073741974
  6 09-28 22:53:26.960: E/123(17442): heightMeasureSpec===-2147482958
  7 09-28 22:53:26.960: E/123(17442): widthMode==1073741824 widthSize===150
  8 09-28 22:53:26.960: E/123(17442): heightMode==-2147483648 heightSize===690
  9 09-28 22:53:26.960: E/123(17442): MeasureSpec.UNSPECIFIED==0
 10 09-28 22:53:26.960: E/123(17442): MeasureSpec.AT_MOST==-2147483648
 11 09-28 22:53:26.961: E/123(17442): MeasureSpec.EXACTLY==1073741824
 12 09-28 22:53:26.961: E/123(17442): widthMeasureSpec===1073741899
 13 09-28 22:53:26.961: E/123(17442): heightMeasureSpec===1073741974
 14 09-28 22:53:26.961: E/123(17442): widthMode==1073741824 widthSize===75
 15 09-28 22:53:26.961: E/123(17442): heightMode==1073741824 heightSize===150
 16 09-28 22:53:27.001: E/123(17442): change===true left===0 top===0 right===75 bottom===75
 17 09-28 22:53:27.030: E/123(17442): MeasureSpec.UNSPECIFIED==0
 18 09-28 22:53:27.031: E/123(17442): MeasureSpec.AT_MOST==-2147483648
 19 09-28 22:53:27.031: E/123(17442): MeasureSpec.EXACTLY==1073741824
 20 09-28 22:53:27.031: E/123(17442): widthMeasureSpec===1073741974
 21 09-28 22:53:27.031: E/123(17442): heightMeasureSpec===-2147482958
 22 09-28 22:53:27.031: E/123(17442): widthMode==1073741824 widthSize===150
 23 09-28 22:53:27.031: E/123(17442): heightMode==-2147483648 heightSize===690
 24 09-28 22:53:27.031: E/123(17442): MeasureSpec.UNSPECIFIED==0
 25 09-28 22:53:27.031: E/123(17442): MeasureSpec.AT_MOST==-2147483648
 26 09-28 22:53:27.031: E/123(17442): MeasureSpec.EXACTLY==1073741824
 27 09-28 22:53:27.032: E/123(17442): widthMeasureSpec===1073741899
 28 09-28 22:53:27.032: E/123(17442): heightMeasureSpec===1073741974
 29 09-28 22:53:27.032: E/123(17442): widthMode==1073741824 widthSize===75
 30 09-28 22:53:27.032: E/123(17442): heightMode==1073741824 heightSize===150
 31 09-28 22:53:27.033: E/123(17442): change===false left===0 top===0 right===75 bottom===75
 32 09-28 22:53:27.045: E/123(17442): onDraw

 

从上面的结果我们可以知道xml中控件加载过程

1.xml中使用的控件,加载的时候,调用的是控件两个参数的方法

public DrawView(Context context, AttributeSet attrs) {
}

一个是上下文,一个是属性

2.解析来会调用

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}

方法,这个方法是用来确定控件的宽高的,这个值是从控件的width、height中读出来的。但是我们发现,这两个值的打印结果很奇怪,甚至还有负数。网上对此的解释是

onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。

具体什么我也不清楚,不过,它其实是包含了很多信息在里面的。一个就是,从这个数值,我们可以获得这个控件宽跟高的形式

使用如下方法

int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);

这个mode的取值,可以有一下三种

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方法传入的模式。

posted @ 2015-09-29 11:17  小白屋  阅读(673)  评论(0)    收藏  举报