View绘制常见问题二:在Activity中获取的View 宽高,得到的值时0
int width = View.getMeasuredWidth();
int height = View.getMeasuredHeight();
1:通过getMeasuredxxx() 获取到的宽或者高如果为0,通常情况是由于,Measure过程还没有测量完毕,你就在Activity生命周期的某个函数去获取它。
2:根本原因是View的 measure过程和Activity的生命周期方法不是同步的,所以无法在Activity生命周期的某个方法执行后View就一定能获取到值,当我们在View还没有完成measure过程就去获取它的宽高,那么当然就是获取不到的,解决这个方法有很多种。
方法一:
在View的post方法种获取:post方法种传入的Runnable对象会在在View的measure 、layout过程后触发,因为Ui的事件队列是按顺序执行的,所以任何post到队列中的请求都会在Layout发生变化后执行。
mView.post(new Runnable() {
@Override
public void run() {
width = mView.getMeasuredWidth();
height = mView.getMeasuredHeight();
}
});
方法二:
使用View的观察者ViewTreeObserver, 它是是视图数的观察者,其中onGlobalLayoutListener监听的是一个视图树中布局发生改变或者某个试图的可视状态发生改变时,就会触发此类监听事件,其中onGlobalLayout回调方法会在View完成layout过程后调用,此时就是获取View宽高的好时机。
但是,这个方法在使用时需要注意的一点是:随之View树的状态改变,onGlobalLayout方法会被调用多次,所以在进入 onGlobalLayout回调方法时,就可以移除这个观察者,保证onGlobalLayout执行一次就可以了。
ViewTreeObserver observer = mView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
width = mScanIv.getMeasuredWidth();
height = mScanIv.getMeasuredHeight();
}
});
方法三:在 onWindowFocusChanged中回调获取,此方法时在View已经初始化完成,measure和layout过程已经执行完毕,UI视图已经渲染完成时被回调,此时View的宽高肯定也已经被确定了,这个时候就可以去获取View的宽高了。
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
width = mView.getMeasuredWidth();
height = mView.getMeasuredHeight();
}
}