大家很多时候需要在Activity或者Fragment的onCreate()方法中获取声明的空间的高度或者宽度,进行位置移动或者其他操作,但是当调用 view.getHeight()
或者 view.getWidth()
获取的竟然为0。。。
其实很容易理解,在onCreate()的时候,实际上控件只是声明了,并没有绘制完成,没有attach到window上,所以导致获取的高度和宽度为0
,那么该怎么解决呢?
三种方式
1、使用下面的post方式
view.post(new Runnable() {@Overridepublic void run() {int height = view.getHeight() ;int width = view.getWidth();}
});
原理:
-
View.post(Runnable) 内部会自动分两种情况处理,当 View 还没 attachedToWindow 时,会先将这些 Runnable 操作缓存下来;否则就直接通过 mAttachInfo.mHandler 将这些 Runnable 操作 post 到主线程的 MessageQueue 中等待执行。
-
如果 View.post(Runnable) 的 Runnable 操作被缓存下来了,那么这些操作将会在 dispatchAttachedToWindow() 被回调时,通过 mAttachInfo.mHandler.post() 发送到主线程的 MessageQueue 中等待执行。
想了解更多请去查看源码。相信你可以更深层次的理解。
View.post() 中的操作执行时,View 的宽高已经计算完毕,所以可以在 Activity 的 onCreate() 里调用 View.post() 来解决获取 View 宽高为0的问题
。
2、使用ViewTreeObserver的方式
ViewTreeObserver vto = view.getRabbit().getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {public boolean onPreDraw() {if(vto.isAlive()){vto.removeOnDrawListener(this);}int height = view.getMeasuredHeight());return true;}
});
ViewTreeObserver 注册一个观察者来监听视图树,当视图树的布局、视图树的焦点、视图树将要绘制、视图树滚动等发生改变时,ViewTreeObserver都会收到通知。所以 这个方法会调用很多次,如果要使用这种方法的话,要做好规避调用多次,记得移除监听
;ViewTreeObserver不能被实例化,可以调用View.getViewTreeObserver()来获得。
3、还有一种不太推荐
@Override
public void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);int height = view.getHeight()int width = view.getHeight();
}
这个函数的含义是:view已经初始化完毕了,宽/高已经准备好了,这个时候去获取宽高是可以成功获取的。需要注意的是 onWindowFocusChanged函数会被调用多次,当Activity的窗口得到焦点和失去焦点时均会被调用一次,如果频繁地进行onResume和onPause,那么onWindowFocusChanged也会被频繁地调用,不太适合处理一些复杂的业务逻辑
。