首先我们看看TextView.java中的onMeasure()源码:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; ... if (widthMode == MeasureSpec.EXACTLY) { // Parent has told us how big to be. So be it. width = widthSize; } else { if (mLayout != null && mEllipsize == null) { des = desired(mLayout); } ... setMeasuredDimension(width, height);首先我们要理解的是widthMeasureSpec, heightMeasureSpec这两个参数是从哪里来的?onMeasure()函数由包含这个View的具体的ViewGroup调用,因此值也是从这个ViewGroup中传入的。这里我直接给出答案:子类View的这两个参数,由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同决定。权值weight也是尤其需要考虑的因素,有它的存在情况可能会稍微复杂点。
<LinearLayout 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" android:gravity="center" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <LinearLayout android:layout_width="200dp" android:layout_height="wrap_content" android:paddingTop="20dp" android:layout_marginTop="30dp" android:background="@android:color/darker_gray" > <com.sean.myview.MyView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="10dp" android:layout_marginTop="15dp" android:background="@android:color/holo_red_light" /> </LinearLayout> </LinearLayout>效果图如下:
package com.sean.myview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class MyView extends View { public MyView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub Log.d("MyView","------", new Throwable()); int speSize = MeasureSpec.getSize(heightMeasureSpec); int speMode = MeasureSpec.getMode(heightMeasureSpec); Log.d("MyView", "---speSize = " + speSize + ""); Log.d("MyView", "---speMode = " + speMode + ""); if(speMode == MeasureSpec.AT_MOST){ Log.d("MyView", "---AT_MOST---"); } if(speMode == MeasureSpec.EXACTLY){ Log.d("MyView", "---EXACTLY---"); } if(speMode == MeasureSpec.UNSPECIFIED){ Log.d("MyView", "---UNSPECIFIED---"); } setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), speSize); } }