美文网首页Android开发AndroidAndroid开发
Android解决在onCreate()中获取View的widt

Android解决在onCreate()中获取View的widt

作者: 齐小政 | 来源:发表于2016-12-03 15:16 被阅读712次

    前言

    • 在activity中,经常需要获取view的width和height,但是在onCreate()获取view的width和height会得到0。view.getWidth()和view.getHeight()为0的根本原因是:控件还没有完成绘制。这种情况当我们使用动态布局(使用wrap_content或match_parent)就会出现。
    • 一般来讲在Activity.onCreate(...)、onResume()方法中都没有办法获取到View的实际宽高。So,我们必须用一种变通的方法,等到View绘制完成后去获取width和Height。
    • 下面有一些可行的解决方案:

    1. 监听Draw/Layout事件:ViewTreeObserver

    ViewTreeObserver监听很多不同的界面绘制事件。一般来说OnGlobalLayoutListener就是可以让我们获得到view的width和height的地方.下面onGlobalLayout内的代码会在View完成Layout过程后调用。

    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mScrollView.post(new Runnable() {
                    public void run() {
                        view.getHeight(); //height可用了
                    }
                });
            }
    });
    

    但是要注意这个方法在每次有些view的Layout发生变化的时候被调用(比如某个View被设置为Invisible),所以在得到你想要的宽高后,记得移除onGlobleLayoutListener:

    在 SDK Lvl < 16时使用
    public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
    
    在 SDK Lvl >= 16时使用
    public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
    
    2. 将一个runnable添加到Layout队列中:View.post()

    这个解决方案是比较好的。简单地说,只要用View.post()一个runnable就可以了。runnable对象中的方法会在View的measure、layout等事件后触发,UI事件队列会按顺序处理事件。在setContentView()被调用后,事件队列中会包含一个要求重新layout的message,所以任何post到队列中的东西都会在Layout发生变化后执行。

    view.post(new Runnable() {
            @Override
            public void run() {
                view.getHeight(); //height可用
            }
        });
    
    3. 重写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可用
        }
    };
    

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

    4. 重写Activity的onWindowFocusChanged方法

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

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        //此处可以正常获取width、height等
    }
    

    在Activity得到或者失去焦点的时候,就会被调用。Activity初始化完毕准备显示的时候就会回调该方法。所以说,只要想做一些Activity加载完毕就马上触发的事情,都可以在这里执行。

    5. 获取固定宽高

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

    View.getMeasureWidth()
    View.getMeasureHeight()
    
    

    相关文章

      网友评论

      • e5efe1b63eb8:第一个方法里面的线程是不必要的吧。不知道楼主有没有遇见过第一种方法里getWidth()获取宽度依然为0的情况,布局是match_parent
        齐小政:刚又去简单测试了下,布局是match_parent是可以正常获取宽度的,https://github.com/qizhenghao/Hello_Android/commit/a018ba17b396d9a0154c47b69009b9ffedc3f159 ,可以把你遇到的情况的事例代码贴一下
      • 俺卓:学习了
      • fd5242e95d94:不错 受益匪浅 请教一下runnable方法会在view的draw方法之前调用么
        齐小政:答案是会的,:smile: ,具体参考我另一篇文章吧,有解释了:http://www.jianshu.com/p/7f5342ceba34
      • BlackNeko:有时候,只是把View inflate出来,但没有画到屏幕上,需要先调用View#measure() ,然后才能用View#getMeasureWidth() :smile:
      • BrokenDust:涨姿势了!
      • pdog18:只知道一个监听回调的方法。原来有这么多方案

      本文标题:Android解决在onCreate()中获取View的widt

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