一般在自定义控件的时候getMeasuredWidth/getMeasuredHeight它的赋值在View的setMeasuredDimension中,所以有时可以在onMeasure方法中看到利用getMeasuredWidth/getMeasuredHeight初始化别的参数。而getWidth/getHeight一直在onLayout完成后才会被赋值。一般情况下,如果都完成了赋值,两者值是相同的.(摘自鸿洋) 参考:(Android视图绘制流程完全解析,带你一步步深入了解View(二))
关于View的onMeasure()、onSizeChanged()、onLayout()、onDraw()调用顺序 调用顺序应该是 构造函数——->onMeasure——->onSizeChanged——->onLayout——->onDraw 后面有可能 onMeasure——->onLayout——->onDraw (摘自here) 并且是在onResume之后。
需要注意的是,在setMeasuredDimension()方法调用之后,我们才能使用getMeasuredWidth()和getMeasuredHeight()来获取视图测量出的宽高,以此之前调用这两个方法得到的值都会是0。
视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在xml文件中指定视图的大小,然后视图本身会对最终的大小进行拍板。 参考:Android视图绘制流程完全解析,带你一步步深入了解View(二)
onLayout、layout
Android的onLayout、layout方法讲解 onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。在实际开发中,一般要配合onMeasure测量方法一起使用。
@OverridePRotected abstract void onLayout(boolean changed, int l, int t, int r, int b);该方法在ViewGroup中定义是抽象函数,继承该类必须实现onLayout方法,而ViewGroup的onMeasure并非必须重写的。View的放置都是根据一个矩形空间放置的,onLayout传下来的l,t,r,b分别是放置父控件的矩形可用空间(除去margin和padding的空间)的左上角的left、top以及右下角right、bottom值。
public void layout(int l, int t, int r, int b);该方法是View的放置方法,在View类实现。调用该方法需要传入放置View的矩形空间左上角left、top值和右下角right、bottom值。这四个值是相对于父控件而言的。例如传入的是(10, 10, 100, 100),则该View在距离父控件的左上角位置(10, 10)处显示,显示的大小是宽高是90(参数r,b是相对左上角的),这有点像绝对布局。
使用方法:
public class MyViewGroup extends ViewGroup { // 子View的水平间隔 private final static int padding = 20; public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub // 动态获取子View实例 for (int i = 0, size = getChildCount(); i < size; i++) { View view = getChildAt(i); // 放置子View,宽高都是100 view.layout(l, t, l + 100, t + 100); l += 100 + padding; } }}自己的测试:
public class CircleProgressView extends View { public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); Log.e(TAG, "333onMeasure: measureHeight=="+measureHeight+"--measureWidth=="+measureWidth+"--height=="+height+"--width=="+width ); } public CircleProgressView(Context context, AttributeSet attrs) { super(context, attrs); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); int left=getLeft(); int right=getRight(); Log.e(TAG, "444构造方法: measureHeight=="+measureHeight+"--measureWidth==" +measureWidth+"--height=="+height+"--width=="+width +"--left=="+left+"--right=="+right); } public CircleProgressView(Context context) { super(context); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); Log.e(TAG, "555onMeasure: measureHeight=="+measureHeight+"--measureWidth=="+measureWidth+"--height=="+height+"--width=="+width ); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。 mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec);//测量后的宽度 mMeasureHeigth = MeasureSpec.getSize(heightMeasureSpec);//测量后的高度 setMeasuredDimension(mMeasureWidth, mMeasureHeigth); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); int left=getLeft(); int right=getRight(); Log.e(TAG, "1111onMeasure: measureHeight=="+measureHeight+"--measureWidth==" +measureWidth+"--height=="+height+"--width=="+width +"--left=="+left+"--right=="+right); initView(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制圆 canvas.drawCircle(mCircleXY, mCircleXY, mRadius, mCirclePaint);//圆心、半径 // 绘制弧线 canvas.drawArc(mArcRectF, 270, mSweepAngle, false, mArcPaint);//起始角度、扫过角度、不用中心 // 绘制文字 canvas.drawText(mShowText, 0, mShowText.length(), mCircleXY, mCircleXY + (mShowTextSize / 4), mTextPaint);//文本,文本的起始与终止,文本位置(要看对齐方式) int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); int left=getLeft(); int right=getRight(); Log.e(TAG, "2222onDraw: measureHeight=="+measureHeight+"--measureWidth==" +measureWidth+"--height=="+height+"--width=="+width +"--left=="+left+"--right=="+right); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); Log.e(TAG, "666onLayout: measureHeight=="+measureHeight+"--measureWidth==" +measureWidth+"--height=="+height+"--width=="+width +"--left=="+left+"--right=="+right); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); int measureHeight=getMeasuredHeight(); int measureWidth=getMeasuredWidth(); int height=getHeight(); int width=getWidth(); int left=getLeft(); int right=getRight(); Log.e(TAG, "777onSizeChanged: measureHeight=="+measureHeight+"--measureWidth==" +measureWidth+"--height=="+height+"--width=="+width +"--left=="+left+"--right=="+right); } private void initView() { float length = 0; if (mMeasureHeigth >= mMeasureWidth) { length = mMeasureWidth; } else { length = mMeasureHeigth; } mCircleXY = length / 2; mRadius = (float) (length * 0.5 / 2); mCirclePaint = new Paint(); mCirclePaint.setAntiAlias(true); mCirclePaint.setColor(getResources().getColor( android.R.color.holo_blue_bright)); mArcRectF = new RectF( (float) (length * 0.1), (float) (length * 0.1), (float) (length * 0.9), (float) (length * 0.9)); mSweepAngle = (mSweepValue / 100f) * 360f; mArcPaint = new Paint(); mArcPaint.setAntiAlias(true); mArcPaint.setColor(getResources().getColor( android.R.color.holo_blue_bright)); mArcPaint.setStrokeWidth((float) (length * 0.1)); mArcPaint.setStyle(Style.STROKE);//描边 mShowText = setShowText(); mShowTextSize = setShowTextSize(); mTextPaint = new Paint(); mTextPaint.setTextSize(mShowTextSize); mTextPaint.setTextAlign(Paint.Align.CENTER); }}log结果:
02-07 10:07:34.930 13920-13920/com.imooc.systemwidget E/ContentValues: 444构造方法:measureHeight==0--measureWidth==0--height==0--width==0--left==0--right==002-07 10:07:34.955 13920-13920/com.imooc.systemwidget E/ContentValues: 1111onMeasure:measureHeight==1692--measureWidth==1080--height==0--width==0--left==0--right==002-07 10:07:35.005 13920-13920/com.imooc.systemwidget E/ContentValues: 1111onMeasure: measureHeight==1692--measureWidth==1080--height==0--width==0--left==0--right==002-07 10:07:35.006 13920-13920/com.imooc.systemwidget E/ContentValues: 777onSizeChanged: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==108002-07 10:07:35.006 13920-13920/com.imooc.systemwidget E/ContentValues: 666onLayout: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==108002-07 10:07:35.023 13920-13920/com.imooc.systemwidget E/ContentValues: 2222onDraw: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==108002-07 10:07:35.092 13920-13920/com.imooc.systemwidget E/ContentValues: 1111onMeasure: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==108002-07 10:07:35.094 13920-13920/com.imooc.systemwidget E/ContentValues: 666onLayout: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==108002-07 10:07:35.095 13920-13920/com.imooc.systemwidget E/ContentValues: 2222onDraw: measureHeight==1692--measureWidth==1080--height==1692--width==1080--left==0--right==1080结论:
1、调用顺序应该是 构造函数——->onMeasure——->onSizeChanged——->onLayout——->onDraw——-> onMeasure——->onLayout——->onDraw 2、getMeasuredWidth()在onmeasure方法中可获取 getWidth()在onSizeChanged、onLayout、onDraw等方法中即可获取。 3、getWidth()=getRight()-getLeft() 4、当getMeasuredWidth()和getWidth()都有值的时候,两者相等。
参考
Android群英传
Android艺术探索