在View的measure完成后,一般可以通过getMeasureWidth/getMeasureWidth方法可以正确的获取View的宽高,而在特殊情况下,可能需要多次measure才能确定最终的测量宽高,onMeasure无法获取正确的宽高,但可以在onLayout方法中获取测量宽高。
而在Activity生命周期方法中,是无法通过getMeasureWidth/getMeasureWidth获取正确的测量宽高,是因为View的measure和Activity的生命周期方法不是同步执行的,因此无法保证Activity执行生命周期方法时View已经绘制完毕,如果没有绘制完,宽高可能是0。可以通过以下四种方法解决这个问题:
1、Acvtivity/View#onWindowFocusChanged
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
}
需要注意的是,这个方法可能会被调用多次,例如onResume和onPause调用,均会调用这个方法。
2、view.post(runnable)
通过post可以将一个runnable投递到消息队列的尾部,等待Looper调用次runnable时候,view已经初始化了。
view.post(new Runnable() {
@Override
public void run() {
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
});
3、ViewTreeObserver
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this::onGlobalLayout);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
});
需要注意,伴随着View树的状态改变,onGlobalLayout()会被调用多次。
4、view.measure(int widthMeasureSpec,int heightMeasureSpec)
通过手动对View进行measure来得到View的宽高,但需要根据不同情况来进行处理
- match_parent
这个无法measure具体的宽高,是因为需要知道父容器的parentSize,但这个时候是无法获取的。
- 具体的数值
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);
- wrap_content
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec, heightMeasureSpec);
网友评论