多种方式获取View 的宽高

Posted by ijays on February 20, 2017

多种方式获取View的宽高

说到获取View 的宽高,一般情况下我们都是直接调用View 的getWidth(),getHeight()方法。然而,当我们需要在Activity 一启动的时候就去获取View 的宽高的时候,这种方式就有问题了。因为View 的测量绘制过程和Activity 的生命周期并不是同步执行,在onCreate、onStart 或者onResume 方法中获取View 的宽高都是不准确的,有可能此时View 已经测量完毕,也有可能尚未测量完毕。此时我们就需要一些不一样的方式来获取View 的宽高。

利用onWindowFocusChanged

onWindowFocusChanged 顾名思义,即当Window 的焦点发生变化时的回调,此时View 已经初始化完毕了,宽高自然也能获取到。需要注意的是,这个方法在Window 获得焦点和失去焦点的时候都会被调用,因此会被多次调用。

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

View.post(runnable)

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

  @Override
    protected void onStart() {
        super.onStart();

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

ViewTreeObserver

这个方法是比较推荐的方法。之前项目中有一个一抹心签的功能,需要对一个DialogFragment 进行截图然后分享出去。实现的思路大概就是获取View 的宽高,创建相同尺寸的画布,将View 投射到画布上,最后输出到文件中。

扯远了……回到获取宽高,通过ViewTreeObserver 的OnGlobalLayoutListener 接口,可以在View 树的状态发生改变或者View 树内部的View 可见性发生时,来获取View 的宽高。同样的,在每次View 树发生状态改变时,这个接口会被多次回调,因此要移除不用的监听器,防止内存泄漏。

  ViewTreeObserver vto = view.getViewTreeObserver();
  vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
           //及时移除监听器
           view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
           int width = mMainContainer.getMeasuredWidth();
           int height = mMainContainer.getMeasuredHeight();
           }
      });