getWidth & getMeasuredWidth 到底有啥不一样?

984 阅读2分钟

起因

故事得从一个小功能说起。最近的一个需求要做一个长按复制标题的功能。这本来是一个很简单的需求,直接给textView设置 android:textIsSelectable="true" 即可。可是它却是要儿子送兄弟。

Markdown
如图所示不止有复制功能还出现了分享。同时,这个属性还有可能导致TextView内的字体能滑动,没错,TextView内的字能滑动了!!!于是,打算自己撸一个类似系统复制的功能。思路也简单用一个PopupWindow实现显示复制图标。然后点击复制内容。嗯,思路没问题。那么我们就用

View popView = LayoutInflater.from(mContext).inflate(R.layout.copy_background, null, false);
        mCopyPopupWindow = new PopupWindow(popView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        mCopyPopupWindow.setOutsideTouchable(true);
        mCopyPopupWindow.setBackgroundDrawable(new BitmapDrawable());
        popView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SystemUtil.copyToClipboard(data);
                mCopyPopupWindow.dismiss();
            }
        });
        mCopyPopupWindow.showAsDropDown(view, view.getWidth() / 2 - popView.getWindth()/2, -popView.getWidth()- view.getHeight());

使其如系统那么显示即可。嗯,so easy。当我把代码写完跑一遍的时候,突然发现显示的位置居然错了。如图所示

Markdown
怎么可能。于是只能打断点找原因。发现getWindth显示的是个0。好吧问题就出在这,于是,找了一下google帮忙。知道问题的原因就是此时我们的popupWindow还未经历过测量布局绘制。所以你去取它的宽当然为0。同时我也获得了解决方法。把getWidth换成getMeasureWidth,同时在showAsDropDown之前加上 popView.measure(0,0);试了一下。容我大笑三声。哈!哈!哈!。
Markdown
那么问题又来了,把getMeasureWidth换成getWidth是否可以。经过测试,发现不行好吧。那么这两个长的差不多的方法到底有什么不同呢?

经过

万事不行看源码。于是我在源码中挖出了这些代码

/**
     * Return the width of the your view.
     *
     * @return The width of your view, in pixels.
     */
    @ViewDebug.ExportedProperty(category = "layout")
    public final int getWidth() {
        return mRight - mLeft;
    }

 /**
     * Like {@link #getMeasuredWidthAndState()}, but only returns the
     * raw width component (that is the result is masked by
     * {@link #MEASURED_SIZE_MASK}).
     *
     * @return The raw measured width of this view.
     */
    public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }
    
    
     /**
     * Width as measured during measure pass.
     * {@hide}
     */
    @ViewDebug.ExportedProperty(category = "measurement")
    int mMeasuredWidth;

从这两端代码的注解以及注释中我们能够知道。getMeasureWidth()获得的宽是对应于View经历了measure过程后存在的,而getWidth()获得的宽是需要View经历了layout过程才会存在。而我们在getMeasureWidth()方法之前调用的Measure(0,0)方法即是让view去经历measure过程。到此,这两个方法的不同有了大致的了解。

结果

知道了这些那我们有什么用呢?我想了一下,平时遇到的一个难题貌似有解了。就是在Activity的onCreate,onStart等方法中如何去获得某个view的长宽,相信聪明的你应该也知道怎么玩了吧。

废话有点多,各位看官轻喷。有啥不对的多多指教