问题:在onCreate、onStart或者onResume方法中无法正确获取某个View的宽高
原因是View的measure过程和Activity的生命周期方法不是同步执行的,因此无法保证Activity执行了onCreate、onStart、onResume时某个View已经测量完毕了,如果View没有测量完毕,那么获得的宽高就是0。
这里给出以下三种方法来解决这个问题:
1. Activity/View的onWindowFocusChanged
onWindowFocusChanged这个方法的含义是:View已经初始化完毕,宽高已经准备好了,这个时候去获取宽高是没有问题的。需要注意的是,onWindowFocusChanged会被调用多次,当Activity的窗口得到焦点和失去焦点的时候都会被调用一次。
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = view.getMeasuredWith();
int height = view.getMeasuredHeight();
}
}
2. view.post(runnable)
通过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();
}
});
}
3. ViewTreeObserver
使用ViewTreeObserver的众多回调接口也可以,比如使用OnGlobalLayoutListener这个接口,当View树的状态发生改变或者View树内部的View的可见性发生改变的时候,onGlobalLayout方法将被回调,因此这是获取View的宽高一个很好的机会。值得注意的是,伴随着View树的状态改变等,onGlobalLayout会被多次调用。
@Override
protected void onStart() {
super.onStart();
ViewTreeObserver observer = tv.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
tv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width = tv.getMeasuredWidth();
int height = tv.getMeasuredHeight();
}
});
}