[Android] 获取View的宽度和高度

作者: wuzhen | 来源:发表于2016-02-04 11:35 被阅读13257次

有时需要在 onCreate() 方法中获取某个 View 组件的宽度和高度,而直接调用 getWidth()getHeight()getMeasuredWidth()getMeasuredHeight() 方法只会得到 0。

实现方法

一、使用 View.measure 测量 View

该方法测量的宽度和高度可能与视图绘制完成后的真实的宽度和高度不一致。

int width = View.MeasureSpec.makeMeasureSpec(0,
        View.MeasureSpec.UNSPECIFIED);
int height = View.MeasureSpec.makeMeasureSpec(0,
        View.MeasureSpec.UNSPECIFIED);
view.measure(width, height);
view.getMeasuredWidth(); // 获取宽度
view.getMeasuredHeight(); // 获取高度

二、使用 ViewTreeObserver. OnPreDrawListener 监听事件

在视图将要绘制时调用该监听事件,会被调用多次,因此获取到视图的宽度和高度后要移除该监听事件。

view.getViewTreeObserver().addOnPreDrawListener(
        new ViewTreeObserver.OnPreDrawListener() {

    @Override
    public boolean onPreDraw() {
        view.getViewTreeObserver().removeOnPreDrawListener(this);
        view.getWidth(); // 获取宽度
        view.getHeight(); // 获取高度
        return true;
    }
});

三、使用 ViewTreeObserver. OnGlobalLayoutListener 监听事件

在布局发生改变或者某个视图的可视状态发生改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。

view.getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        if (Build.VERSION.SDK_INT >= 16) {
            view.getViewTreeObserver()
                    .removeOnGlobalLayoutListener(this);
        }
        else {
            view.getViewTreeObserver()
                    .removeGlobalOnLayoutListener(this);
        }
        view.getWidth(); // 获取宽度
        view.getHeight(); // 获取高度
    }
});

四、重写 View 的 onSizeChanged 方法

在视图的大小发生改变时调用该方法,会被多次调用,因此获取到宽度和高度后需要考虑禁用掉代码。
该实现方法需要继承 View,且多次被调用,不建议使用

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    view.getWidth(); // 获取宽度
    view.getHeight(); // 获取高度
}

五、重写 View 的 onLayout 方法

该方法会被多次调用,获取到宽度和高度后需要考虑禁用掉代码。
该实现方法需要继承 View,且多次被调用,不建议使用

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    view.getWidth(); // 获取宽度
    view.getHeight(); // 获取高度
}

六、使用 View.OnLayoutChangeListener 监听事件(API >= 11)

在视图的 layout 改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。

view.addOnLayoutChangeListener(
        new View.OnLayoutChangeListener() {

    @Override
    public void onLayoutChange(View v, int l, int t, int r, int b,
            int oldL, int oldT, int oldR, int oldB) {
        view.removeOnLayoutChangeListener(this);
        view.getWidth(); // 获取宽度
        view.getHeight(); // 获取高度
     }
});

七、使用 View.post() 方法

Runnable 对象中的方法会在 View 的 measure、layout 等事件完成后触发。
UI 事件队列会按顺序处理事件,在 setContentView() 被调用后,事件队列中会包含一个要求重新 layout 的 message,所以任何 post 到队列中的 Runnable 对象都会在 Layout 发生变化后执行。
该方法只会执行一次,且逻辑简单,建议使用

view.post(new Runnable() {

    @Override
    public void run() {
        view.getWidth(); // 获取宽度
        view.getHeight(); // 获取高度
    }
});

参考:

stackoverflow: getWidth() and getHeight() of View returns 0

源码:

GitHub: MeasureViewDemo

相关文章

网友评论

  • baa0ac740b1f:好像可以?
  • 32e44e92fc06:View.measure 如果只使用一 这种方式,怎么才能解决测量的宽度和高度可能与视图绘制完成后的真实的宽度和高度不一致的问题呢
    唐鑫儿:兄嘚 你找到解决办法了没
  • 704c25adb7a5:lz,我使用方法一,得到的结果还是0, 请问何解?
    DrunkPian0:makeMeasureSpec的第一个参数不应该填0。具体填什么要看情况。第一个参数的size是一个int,但是只有低30位能用,低30位表示size大小,高2位表示模式。比如你是Wrapcontent,那就应该这么写:
    makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST)
  • pandabyte:post 方法赞!!!
  • 76ffef5441ab:楼主 onsizechange 可以得到控件的宽高, onmesure 也可以 这 onmesure 不断地 测量 会不断地接近onsizechange 的值, 我想问的的是 ,为什么有的时候别人不从写 onmesure 而是重写onsizechange 啊 ,
  • 修得养得梦得过得:很全面 ,真心点个赞先。

    addOnLayoutChangeListener 我觉得更好,在回调中就直接返回了View 对象 。

本文标题:[Android] 获取View的宽度和高度

本文链接:https://www.haomeiwen.com/subject/ihaskttx.html