本文主要是介绍getWidth()与getMeasuredWidth()的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
getWidth()与getMeasuredWidth()的区别
一般在自定义控件的时候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(二)
onMeasure多次调用问题
Android如何绘制视图,解释了为何onMeasure有时要调用多次
为什么FlowLayout的 onMeasure方法会执行4次,onLayout方法会执行两次呢,
父视图可能在它的子视图上调用一次以上的measure(int,int)方法。例如,父视图可以使用unspecified dimensions来将它的每个子视图都测量一次来算出它们到底需要多大尺寸,如果所有这些子视图没被限制的尺寸的和太大或太小,那么它会用精确数值再次调用measure()(也就是说,如果子视图不满意它们获得的区域大小,那么父视图将会干涉并设置第二次测量规则)。
测试:
@SuppressWarnings("deprecation")
public class MyActivity extends FragmentActivity {@TargetApi(Build.VERSION_CODES.LOLLIPOP)@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.test3);Display display = getWindowManager().getDefaultDisplay();int displayWidth = display.getWidth();int displayHeight = display.getHeight();Log.e("111", "display.getWidth()==" + displayWidth);//1080Log.e("111", "display.getHeight()==" + displayHeight);//1812Log.e("111", "densityDpi==" + getResources().getDisplayMetrics().densityDpi);//480Log.e("111", "density==" + getResources().getDisplayMetrics().density);//3.0int statusHeight = getStatusHeight(this);Log.e("111", "statusHeight==" + statusHeight);//72Log.e("111", "displayHeight-statusHeight==" + (displayHeight - statusHeight));//1740int actionBarHeight = getActionBarHeight(this);Log.e("111", "actionBarHeight==" + actionBarHeight);//168Log.e("111", "statusHeight+statusHeight==" + (statusHeight + actionBarHeight));//240Log.e("111", "displayHeight-(statusHeight + actionBarHeight)==" + (displayHeight - (statusHeight + actionBarHeight)));//1572}public int getStatusHeight(Context context) {int statusHeight = -1;try {Class<?> clazz = Class.forName("com.android.internal.R$dimen");Object object = clazz.newInstance();int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());statusHeight = context.getResources().getDimensionPixelSize(height);} catch (Exception e) {e.printStackTrace();}return statusHeight;}public int getActionBarHeight(Context context) {TypedValue localTypedValue = new TypedValue();if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, localTypedValue, true)) {return TypedValue.complexToDimensionPixelSize(localTypedValue.data, context.getResources().getDisplayMetrics());}return 0;}}
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#e5e5e5"android:orientation="vertical"><com.android.imooc.RoundImageView
android:layout_width="match_parent"android:layout_height="match_parent"android:background="#6e6e6e"/>
</LinearLayout>
@SuppressLint("AppCompatCustomView")
public class RoundImageView extends ImageView {private Paint mPaint;private Bitmap bitmap;private Matrix mMatrix;private int mWidth;private int mRadius;private BitmapShader bitmapShader;private RectF mRoundRect;public RoundImageView(Context context) {super(context);init();}public RoundImageView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPaint = new Paint();mPaint.setAntiAlias(true);mMatrix = new Matrix();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.e("111", ".......onMeasure.......");Log.e("111", "0getHeight......." + getHeight());//0Log.e("111", "0getWidth......." + getWidth());//0//1560->1740(调用了两次onmeasure,第二次的1740=屏幕高1812-状态栏高72)Log.e("111", "0getMeasuredHeight......." + getMeasuredHeight());//1080->1080(调用了两次onmeasure)Log.e("111", "0getMeasuredWidth......." + getMeasuredWidth());Log.e("111", "0getSuggestedMinimumHeight......." + getSuggestedMinimumHeight());//0Log.e("111", "0getSuggestedMinimumWidth......." + getSuggestedMinimumWidth());//0mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());mRadius = mWidth / 2;setMeasuredDimension(mWidth, mWidth);//1080Log.e("111", ".......onMeasure......................");Log.e("111", "0getHeight......." + getHeight());//0Log.e("111", "0getWidth......." + getWidth());//0Log.e("111", "0getMeasuredHeight......." + getMeasuredHeight());//1080->1080Log.e("111", "0getMeasuredWidth......." + getMeasuredWidth());//1080-->1080Log.e("111", "0getSuggestedMinimumHeight......." + getSuggestedMinimumHeight());//0Log.e("111", "0getSuggestedMinimumWidth......." + getSuggestedMinimumWidth());//0}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);Log.e("111", ".......onSizeChanged.......");Log.e("111", "1getHeight......." + getHeight());//1080(setMeasuredDimension决定)Log.e("111", "1getWidth......." + getWidth());//1080Log.e("111", "1getMeasuredHeight......." + getMeasuredHeight());//1080Log.e("111", "1getMeasuredWidth......." + getMeasuredWidth());//1080Log.e("111", "1getSuggestedMinimumHeight......." + getSuggestedMinimumHeight());//0Log.e("111", "1getSuggestedMinimumWidth......." + getSuggestedMinimumWidth());//0mRoundRect = new RectF(0, 0, getWidth(), getHeight());}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);Log.e("111", ".......onLayout.......");Log.e("111", "2getHeight......." + getHeight());//1080Log.e("111", "2getWidth......." + getWidth());//1080Log.e("111", "2getMeasuredHeight......." + getMeasuredHeight());//1080Log.e("111", "2getMeasuredWidth......." + getMeasuredWidth());//1080Log.e("111", "2getSuggestedMinimumHeight......." + getSuggestedMinimumHeight());//0Log.e("111", "2getSuggestedMinimumWidth......." + getSuggestedMinimumWidth());//0}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Log.e("111", ".......onDraw.......");Log.e("111", "3getHeight......." + getHeight());//1080Log.e("111", "3getWidth......." + getWidth());//1080Log.e("111", "3getMeasuredHeight......." + getMeasuredHeight());//1080Log.e("111", "3getMeasuredWidth......." + getMeasuredWidth());//1080Log.e("111", "3getSuggestedMinimumHeight......." + getSuggestedMinimumHeight());//0Log.e("111", "3getSuggestedMinimumWidth......." + getSuggestedMinimumWidth());//0bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);Log.e("111", ".bitmap.getHeight......." + bitmap.getHeight());//300Log.e("111", ".bitmap.getWidth........" + bitmap.getWidth());//300bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);int bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());float scale = mWidth * 1.0f / bSize;mMatrix.setScale(scale, scale);bitmapShader.setLocalMatrix(mMatrix);mPaint.setShader(bitmapShader);Log.e("111", "===drawCircle==mRadius=" + mRadius);//540canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);}
}
activity 用了NoActionBar的style
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!--改变光标、下划线、floatText的颜色--><item name="colorAccent">#ff4081</item></style>
为什么getSuggestedMinimumHeight、Width打印为零
我们修改布局:添加 android:minHeight=”100dp”和android:minWidth=”100dp”
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#e5e5e5"android:orientation="vertical"><com.android.imooc.RoundImageView
android:layout_width="match_parent"android:layout_height="match_parent"android:background="#6e6e6e"android:minHeight="100dp"android:minWidth="100dp" />
</LinearLayout>
再次打印如下:
可见android:minHeight影响了getSuggestedMinimumHeight,
而且getSuggestedMinimumHeight默认为零。
display.getWidth()==1080
display.getHeight()==1812
densityDpi==480
density==3.0
statusHeight==72
displayHeight-statusHeight==1740
actionBarHeight==168
statusHeight+statusHeight==240
displayHeight-(statusHeight + actionBarHeight)==1572.......onMeasure.......
0getHeight.......0
0getWidth.......0
0getMeasuredHeight.......1560
0getMeasuredWidth.......1080
0getSuggestedMinimumHeight.......300
0getSuggestedMinimumWidth.......300
.......onMeasure......................
0getHeight.......0
0getWidth.......0
0getMeasuredHeight.......1080
0getMeasuredWidth.......1080
0getSuggestedMinimumHeight.......300
0getSuggestedMinimumWidth.......300.......onMeasure.......
0getHeight.......0
0getWidth.......0
0getMeasuredHeight.......1740
0getMeasuredWidth.......1080
0getSuggestedMinimumHeight.......300
0getSuggestedMinimumWidth.......300
.......onMeasure......................
0getHeight.......0
0getWidth.......0
0getMeasuredHeight.......1080
0getMeasuredWidth.......1080
0getSuggestedMinimumHeight.......300
0getSuggestedMinimumWidth.......300.......onSizeChanged.......
1getHeight.......1080
1getWidth.......1080
1getMeasuredHeight.......1080
1getMeasuredWidth.......1080
1getSuggestedMinimumHeight.......300
1getSuggestedMinimumWidth.......300.......onLayout.......
2getHeight.......1080
2getWidth.......1080
2getMeasuredHeight.......1080
2getMeasuredWidth.......1080
2getSuggestedMinimumHeight.......300
2getSuggestedMinimumWidth.......300.......onDraw.......
3getHeight.......1080
3getWidth.......1080
3getMeasuredHeight.......1080
3getMeasuredWidth.......1080
3getSuggestedMinimumHeight.......300
3getSuggestedMinimumWidth.......300.bitmap.getHeight.......300
.bitmap.getWidth........300
===drawCircle==mRadius=540
onLayout、layout
Android的onLayout、layout方法讲解
onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。在实际开发中,一般要配合onMeasure测量方法一起使用。
@Override
protected 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}@Overrideprotected 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,宽高都是100view.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 );}@Overrideprotected 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();}@Overrideprotected 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);}@Overrideprotected 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);}@Overrideprotected 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艺术探索
这篇关于getWidth()与getMeasuredWidth()的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!