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;
- }
- <?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-->