关于如何在获取View的宽高
如果直接在 onCreate()
中获取View的宽高的话会直接返回0,甚至在 onResume()
中也是这样,因为这个时候 UI 界面布局还未完成。要获取View的宽高参数必须要的等到绘制过程完成(特别是一些动态的参数 wrap_content
和 match_parent
),但是通常在 onResume()
时还未完成,所以需要等到绘制过程完全结束。
监听绘制事件:ViewTreeObserver
ViewTreeObserver
将被各种绘制事件触发,通常 OnGlobalLayoutListener
就是用来监听测量结果的,这里的代码将在测量结束时调用。
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight();
}
});
注意:这个监听用完必须立即移除,否则将被每个布局事件触发。
布局队列中添加线程 View.post()
只需要在 View 的 post()
方法中添加runnable实现。添加到这个队列的代码基本上会在 View 的 measure()
layout()
等方法结束之后调用。
UI事件队列将顺序的处理。在 setContentView()
被调用之后,这个事件队列将包含要求重新布局的消息,所以添加到这个队列的代码将在布局完成之后被调用。
view.post(new Runnable() {
@Override
public void run() {
view.getHeight();
}
});
比 ViewTreeObserver: 需要在代码执行完后取消观察者(并且可能会忘记)更加方便,语法也简洁。
重写 View 的 onLayout 方法
只有当其他代码逻辑可以被封装在view内部才会显得实用。
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight();
}
};
注意: onLayout()
将被多次调用,所以要清楚自己的方法做了什么 会影响什么,或者考虑只让代码执行一次:
if(isFirst){
view.getHeight();
}
检查是否布局完成
如果代码将在创建 UI 界面的时候多次执行,可以考虑如下的方法:
// view : 需要被测量宽高
if(ViewCompat.isLaidOut(view)) {
view.getHeight();
}
在到达或离开屏幕后 view 至少一次被布局之后,if
内 ViewCompat.isLaidOut(view)
将返回 true
。
获取静态定义的值
如果定义的静态宽或高的值就足够了,可以简单的使用:
View.getMeasuredWidth()
View.getMeasuredHeigth()
注意:这个值可能会与绘制后实际的值不同。
本篇完全是翻译了
参考资料:
Stack Overflow