View的getWidth()和getMeasuredWidth()有什么区别吗?如何在onCreate中拿到View的宽度和高度?

来源:互联网 发布:网络效应和锁定效应 编辑:程序博客网 时间:2024/06/05 17:43
一、View的getWidth()和getMeasuredWidth()有什么区别吗?
getMeasuredWidth()获取的是view原始的大小,也就是这个view在XML文件中配置或者是代码中设置的大小。getWidth()获取的是这个view最终显示的大小,这个大小有可能等于原始的大小也有可能不等于原始大小。
 从源码上开始分析一下这两个方法的区别。首先来看一下getMeasuredWidth()这个方法。
public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

  protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

  private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }
   从源码上来看,getMeasuredWidth()获取的是mMeasuredWidth的这个值。这个值是一个8位的十六进制的数字,高两位表示的是这个measure阶段的Mode的值,具体可以查看MeasureSpec的原理。这里mMeasuredWidth & MEASURED_SIZE_MASK表示的是测量阶段结束之后,view真实的值。而且这个值会在调用了setMeasuredDimensionRaw()函数之后会被设置。所以getMeasuredWidth()的值是measure阶段结束之后得到的view的原始的值。


  再来看看getWidth()的源码:
1   public final int getWidth() {
2         return mRight - mLeft;
3     }
 那么问题来了,mRight和mLeft是什么值,是在什么时候被设置的。我们再看layout阶段的源码:


 在layout阶段会去调用setOpticalFrame()或者调用setFrame()方法,从源码中可知setOpticalFrame()方法,最终还是调用的setFrame()方法。
所以最终的mLeft和mRight的值是在setFrame()方法中被设置的。而且这些mLeft,mRight代表了view最终显示在界面中的大小。


二、如何在onCreate中拿到View的宽度和高度?
在Android中,有时我们需要测量控件的宽度和高度进行一些运算,特别是在自适应屏幕的时候,这些计算就变得特别必要,但是,如果我们直接在onCreate,或者onStart、onResume(第一次执行时)方法,去获取控件的宽度和高度时,得出的结果会是0。
原因是,在执行这几个方法时,窗口Window对象并没有创建完成,而只是做了一些初始化的操作,想要获取控件的宽度和高度就要等到onDraw方法执行完成之后。那么我们怎么知道,控件什么时候绘制完成,并切去获取控件的宽度和高度呢。
方式1、Android为我们提供了这样的机制,利用View类中getViewTreeObserver()方法,为控件添加一个观察者,在控件绘制前进行回调,这样我么就可以获取控件绘制完成之后的宽度以及高度:
[java] view plain copy
tv.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {  
  
            @Override  
            public boolean onPreDraw() {  
                if (!hasDraw) {  
                    Log.e(TAG,  
                            tv.getMeasuredWidth() + "=="  
                                    + tv.getMeasuredWidth());  
                    hasDraw = true;  
                }  
                return true;  
            }  
        });  


方式2:监听View的可视状态的变化,View进行绘制之后,可视状态会改变,这时候我们就可以使用View类中的getViewTreeObserver().addOnGlobalLayoutListener,来给控件添加一个观察者:
[java] view plain copy
tv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  
              
            @Override  
            public void onGlobalLayout() {  
                Log.e(TAG,  
                        tv.getMeasuredWidth() + "=="  
                                + tv.getMeasuredWidth());  
            }  
        });  
阅读全文
0 0
原创粉丝点击