理解onMeasure

        Android系统调用onMeasure来定义view的大小,很长时间理解不是很透彻,今天花了些时间打日志来理解它。总结如下。

        1. widthMeasureSpec和heightMeasureSpec这两个值是android:layout_width="200dp" android:layout_height="80dp"来定义的,它由两部分构成,可通过int specModeHeight = MeasureSpec.getMode(heightMeasureSpec); int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec)来得到各自的值。

如果android:layout_width="wrap_content"或android:layout_width="fill_parent",哪么得到的specMode为MeasureSpec.AT_MOST,如果为精确的值则为MeasureSpec.EXACTLY。另外,specSize要想得到合适的值需要在Androidmanifest.xml中添加<uses-sdk android:minSdkVersion="10" />

        2.系统默认的onMeasure调用方法是getDefaultSize来实现,有时候在自定义控件的时候多数采用        

       

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);

            getDefaultSize代码如下:

           

    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;
    }
          3.onMeasure好像会调用两次,这点我没有到代码中具体跟踪了,如果该view的父view是RelativeLayout,则其父view的onMeasur也要测量一下。我在测试中用的xml为:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

	<com.goso.ui.record.RecordView
		android:id="@+id/uvMeter" 
		android:layout_width="200dp"
		android:layout_height="80dp" 
		android:layout_centerInParent="true" />
</RelativeLayout>
<!-- RelativeLayout  LinearLayout-->

	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
    	int specModeHeight = MeasureSpec.getMode(heightMeasureSpec);
    	int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec);
    	Log.e("HJJ", "****specModeHeight:" + getModeStr(specModeHeight) + ", specSizeHeight:" + specSizeHeight );

    	int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		setMeasuredDimension(widthSize, heightSize);
	}

打印出的结果为:

01-06 12:47:53.170: ERROR/HJJ(5639): ****specModeHeight:AT_MOST, specSizeHeight:714
01-06 12:47:53.170: ERROR/HJJ(5639): ****specModeHeight:EXACTLY, specSizeHeight:120
01-06 12:47:53.190: ERROR/HJJ(5639): ****specModeHeight:AT_MOST, specSizeHeight:714
01-06 12:47:53.190: ERROR/HJJ(5639): ****specModeHeight:EXACTLY, specSizeHeight:120

如果将RelativeLayout换成LinearLayout则为

01-06 12:51:17.980: ERROR/HJJ(5779): ****specModeHeight:EXACTLY, specSizeHeight:120
01-06 12:51:18.010: ERROR/HJJ(5779): ****specModeHeight:EXACTLY, specSizeHeight:120





测试用的代码如下:

package com.goso.ui.record;

import com.goso.ui.R;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class RecordView extends View{
    static final float PIVOT_RADIUS = 3.5f;
    static final float PIVOT_Y_OFFSET = 10f;
    static final float SHADOW_OFFSET = 2.0f;
    static final float DROPOFF_STEP = 0.18f;
    static final float SURGE_STEP = 0.35f;
    static final long  ANIMATION_INTERVAL = 70;
    
    Paint mPaint, mShadow;
	public RecordView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		init(context);
	}

	public RecordView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		init(context);
	}

	private void init(Context context){
	   Drawable bg = context.getResources().getDrawable(R.drawable.vumeter);
	   setBackgroundDrawable(bg);
	   
	   mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	   mPaint.setColor(Color.WHITE);
	   mShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
	   mShadow.setColor(Color.argb(60, 0, 0, 0));
	}
	
    private String getModeStr(int mode){
    	String modeStr = null;
    	switch (mode) {
        case MeasureSpec.UNSPECIFIED:
        	modeStr = "UNSPECIFIED";
            break;
        case MeasureSpec.AT_MOST:
        	modeStr = "AT_MOST";
        	break;
        case MeasureSpec.EXACTLY:
        	modeStr = "EXACTLY";
            break;
        }
    	return modeStr;
    }
    
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
//    	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    	int specModeWidth = MeasureSpec.getMode(widthMeasureSpec);
    	int specSizeWidth = MeasureSpec.getSize(widthMeasureSpec);
    	int specModeHeight = MeasureSpec.getMode(heightMeasureSpec);
    	int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec);
    	//Log.e("HJJ", "specModeWidth:" + getModeStr(specModeWidth) + ", specSizeWidth:" + specSizeWidth );
    	Log.e("HJJ", "****specModeHeight:" + getModeStr(specModeHeight) + ", specSizeHeight:" + specSizeHeight );
//    	Log.e("HJJ", "widthMeasureSpec:" + widthMeasureSpec + ", heightMeasureSpec:" + heightMeasureSpec );
//    	int widthSize = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
//		int heightSize = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    	
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		setMeasuredDimension(widthSize, heightSize);
//		Log.e("HJJ", "width:" + widthSize + ", height:" + heightSize );
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		
		float w = getWidth();
		float h = getHeight();
		float pivotX = w / 2;
		float pivotY = h - PIVOT_RADIUS - PIVOT_Y_OFFSET;
		
		float l = h * 7 / 10;
		float angle = (float) Math.PI * 1/ 8;
		
		float sin = (float) Math.sin(angle);
		float cos = (float) Math.cos(angle);
		
		float x0 = pivotX - l * cos;
		float y0 = pivotY - l * sin;
		
        canvas.drawLine(x0 + SHADOW_OFFSET, y0 + SHADOW_OFFSET, pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, mShadow);
        canvas.drawCircle(pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, PIVOT_RADIUS, mShadow);
        canvas.drawLine(x0, y0, pivotX, pivotY, mPaint);
        canvas.drawCircle(pivotX, pivotY, PIVOT_RADIUS, mPaint);
		
		
	}
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

	<com.goso.ui.record.RecordView
		android:id="@+id/uvMeter" 
		android:layout_width="200dp"
		android:layout_height="80dp" 
		android:layout_centerInParent="true" />
</LinearLayout>
<!-- RelativeLayout  LinearLayout-->


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值