Android获取View的width和Height为0的解决方法

一、前言:

实际上在 onCreate、onStart、onResume中均无法正确得到某个 View 的宽/高信息,这是因为 View 的 measure 过程和 Activity 的生命周期方法不是同步执行的,因此无法保证 Activity 执行了onCreate、onStart、onResume时某个 View 已经测量完毕。如果没有测量完毕,那么获得的宽/高就是 0。

当我们动态创建某些View时,需要通过获取他们的width和height来确定别的View的布局,但是在onCreate()获取view的width和height会得到0。View.getWidth()和View.getHeight()为0的根本原因是控件还没有完成绘制,你必须等待系统将绘制完View时才能获得。

二、解决方案:

1. Activity/View#onWindowFocusChanged

onWindowFocusChanged这个方法的含义是:View 已经初始化完毕,宽/高已经准备好了,这个时候去获取宽/高时没问题的。需要注意的是,onWindowFocusChanged会被调用多次,当 Activity 的窗口得到焦点和失去焦点时,均会被调用一次。如果频繁地进行 onResume 和 onPause,那么onWindowFocusChanged也会频繁地调用。

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            int width = btn_weak.getMeasuredWidth();
            int height = btn_weak.getMeasuredHeight();
        }
    }

2. 监听Draw/Layout事件:ViewTreeObserver

ViewTreeObserver监听很多不同的界面绘制事件。一般来说OnGlobalLayoutListener就是可以让我们获得到view的width和height的地方.下面onGlobalLayout内的代码会在View完成Layout过程后调用。
注意:伴随着 View 树的状态改变等,onGlobalLayout会被调用多次。

ViewTreeObserver observer = view.getViewTreeObserver();
  observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
                btn_weak.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        int width = view.getWidth();
        int height = view.getHeight();
         }
        });

3. View.post(runnable)

通过 post 可以将一个 runnable 投递到消息队列的尾部,然后等待 Looper 调用此 runnable 的时候,View 也已经初始化好了。

UI事件队列会按顺序处理事件。在setContentView()被调用后,事件队列中会包含一个要求重新layout的message,所以任何你post到队列中的东西都会在Layout发生变化后执行。

view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getWidth();
               int height = view.getHeight();
            }
        });

这个方法比ViewTreeObserver好:
1、你的代码只会执行一次,而且你不用在在每次执行后将Observer禁用,省心多了。
2、语法很简单

4. 重写View的onLayout方法

这个方法只在某些场景中实用,比如当你所要执行的东西应该作为他的内在逻辑被内聚、模块化在view中,否者这个解决方案就显得十分冗长和笨重。

view = new View(this) {
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        view.getHeight(); //height is ready
    }
};

需要注意的是onLayout方法会调用很多次,所以要考虑好在这个方法中要做什么,或者在第一次执行后禁用掉你的代码。

5. 获取View固定宽高

如果你要获取的View的width和height是固定的,那么你可以直接使用:

View.getMeasureWidth()
View.getMeasureHeight()

但是要注意,这两个方法所获取的width和height可能跟实际draw后的不一样。官方文档解释了不同的原因:

View的大小由width和height决定。一个View实际上同时有两种width和height值。

第一种是measure width和measure height。他们定义了view想要在父View中占用多少width和height(详情见Layout)。measured height和width可以通过getMeasuredWidth() 和 getMeasuredHeight()获得。

第二种是width和height,有时候也叫做drawing width和drawing
height。这些值定义了view在屏幕上绘制和Layout完成后的实际大小。这些值有可能跟measure
width和height不同。width和height可以通过getWidth()和getHeight获得。


参考链接:https://blog.csdn.net/lufengdie/article/details/48003631

你可能感兴趣的:(Android获取View的width和Height为0的解决方法)