View获取宽高的方法与细节

2,614 阅读1分钟

1. View的getWidth()和getMeasuredWidth()有什么区别吗?

getWidth是获取控件真实的宽度,在view.onlayout之后才能获取到。

getMeasuredWidth()是获取的计算宽度,在view.onmeasure之后获取。 会受到measure影响,而结果不同.

    @ViewDebug.ExportedProperty(category = "layout")
    public final int getWidth() {
        return mRight - mLeft;
    }
    public final int getMeasuredWidth() {
        return mMeasuredWidth & MEASURED_SIZE_MASK;
    }

2.如何在OnCreate中拿到View的宽度和高度?

  1. view.post(runnable) 使用 主线程的handle发送message

    能保证获取的原因是因为:

    具体原因

    oncreate 的时候 mAttachInfo 还为空,那些 Runnable 并没有马上被执行,而是保存到 RunQueue 里面。 执行的接口就是 RunQueue.executeActions,其内部也看到是调用 Handler 执行的,RunQueue.executeActions() 这个接口在整个 ViewRootImpl 里只有一个地方调用,就是在 performTraversals.

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }
  1. ViewTreeObserver.addOnPreDrawListener / ViewTreeObserver.addOnGlobalLayoutListener

    在draw之前获取监听(屏幕是黑屏时,OnCreate获取的还是0)

    ViewTreeObserver.addOnGlobalLayoutListener
    可见性发送变化时(这个更适合)

        final ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                Log.e("TAG","onPreDraw:"+textView.getWidth());
                textView.getViewTreeObserver().removeOnPreDrawListener(this);
                return false;
            }
        });

        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Log.e("TAG","onGlobalLayout:"+textView.getWidth());
                textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
  1. textView.addOnLayoutChangeListener

    在view的layout的时候

            if (li != null && li.mOnLayoutChangeListeners != null) {
                ArrayList<OnLayoutChangeListener> listenersCopy =
                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                int numListeners = listenersCopy.size();
                for (int i = 0; i < numListeners; ++i) {
                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
                }
            }