Android-Daily-Interview icon indicating copy to clipboard operation
Android-Daily-Interview copied to clipboard

2019-08-28:谈一谈获取View宽高的几种方法?

Open MoJieBlog opened this issue 6 years ago • 8 comments

MoJieBlog avatar Aug 28 '19 01:08 MoJieBlog

view.post一个就行了 一把梭

DaveBoy avatar Aug 28 '19 01:08 DaveBoy

1.OnGlobalLayoutListener获取 2.OnPreDrawListener获取 3.OnLayoutChangeListener获取 4.重写View的onSizeChanged() 5.使用View.post()方法

zhaoerlei1989 avatar Aug 28 '19 01:08 zhaoerlei1989

使用MessageQueue.addIdleHandler()也可以获取,而且可以防止多次调用。

uarenothingx avatar Aug 28 '19 01:08 uarenothingx

使用View.post()方法 Context.runOnUiThread(new Runnable() OnGlobalLayoutListener获取 OnPreDrawListener获取 OnLayoutChangeListener获取 重写View的onSizeChanged()

gabyallen avatar Aug 28 '19 03:08 gabyallen

先说下问题的考点:

首先,在 view 测量过后就可以获得 view 的测量宽高,另外系统可能需要多次 measure 才能确定最终的测量宽高。 其次,由于 view 的测量过程和 Activity 的生命周期不是同步,所以无法保证在 onCreate,onStart, onResume 时已经测量完毕,如果没有测量完毕获取的宽高都是0。

能获取真实 view 宽高的方法:

  • Activity/View 的 onWindowFocusChanged 方法: 方法含义是 View 已经初始完毕,宽高已经准备好了, 得到焦点和失去焦点会被多次调用
  • view.post:将 Runnable 投递到消息队列的尾部,当执行到的时候,view 已经初始化好了
  • ViewTreeObserver: 使用 ViewTreeObserver 众多回调可以完成这功能,比如 onGlobalLayoutListener,会调用多次
  • view.addOnLayoutChangeListener

huazidev avatar May 30 '20 04:05 huazidev

1 通过 looper 队列

/**
 * 通过 looper 队列
 */
private void getHeight1() {
    tvText.post(new Runnable() {
        @Override
        public void run() {
            int height = tvText.getHeight();
            Log.i(TAG, "MainActivity;getHeight1;height=" + height);
        }
    });
}

2 当视图树的布局发生改变时

/**
 * 当视图树的布局发生改变时
 */
private void getHeight2() {
    tvText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            tvText.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            int height = tvText.getHeight();
            Log.i(TAG, "MainActivity;getHeight2;height=" + height);
        }
    });
}

3 当视图树的进行绘制时

/**
 * 当视图树的进行绘制时
 */
private void getHeight3() {
    tvText.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            tvText.getViewTreeObserver().removeOnPreDrawListener(this);

            int height = tvText.getHeight();
            Log.i(TAG, "MainActivity;getHeight3;height=" + height);
            return false;
        }
    });
}

4 view 布局改变时

/**
 * view 布局改变时
 */
private void getHeight4() {
    tvText.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
            tvText.removeOnLayoutChangeListener(this);
            int height = tvText.getHeight();
            Log.i(TAG, "MainActivity;getHeight4;height=" + height);
        }
    });
}

liyanfei250 avatar Dec 23 '20 08:12 liyanfei250

通过view.post Runnable方法里面通过view.getHeight

mlinqirong avatar Dec 20 '21 08:12 mlinqirong

看了上方的回答,发现“答不对题”;题目是:获取View宽高的几种方法;回答应该是获取方法,而上文回答的全是”获取时机“

  1. 获取时机:上文都说过了。而且都是能获取到的时机。其实获取不到的时候,判断一下,等有的时候,再存内存里面就可以了。
  2. 获取方法: a. getWidth() 和 getHeight() 方法,本质上是等view宽高计算结束,取内存的值。 b. getMeasureWidth 和 getMeasureHeight 方法,本质上是measure结束,取内存的值。 c. View 的宽高本身是可以写死的。那么就可以直接 取值。任何时机结果都是对的。【例如铺满横屏,有时候可以取屏幕宽度】 d. 取业务缓存。这个依据特定场景,例如:同一个手机,上下滑动直播间,共用的同一个Activity,那么界面的高度,是可以复用的。即:第一次获取完成之后,就可以一直用这个高度值。

yline avatar Sep 02 '23 01:09 yline