Android View工作机制(4)— 我们该什么时候获取View的高宽?
2016-06-11 15:01
459 查看
通过前面三篇总结,我们对View的measure有了一定的了解,那现在考虑一种情况,Activity启动的时候获取某个View的宽高值,该怎么取出呢? 我们现在onCreate或者onStart方法中实验一下, 我们在布局文件中添加一个TextView,命名为tv1。 在onCreate或者onStart中加入Log
Log.d("tvWidth", String.valueOf(tv1.getWidth())); Log.d("tvHeight", String.valueOf(tv1.getHeight()));
可以发现,结果打印出来的都是0。这是为什么呢?因为View的measure过程和Activity周期并不同步执行。所以Activity执行到它的生命周期中的某个方法的时候,并不能保证View已经measure完毕。只要measure过程没有结束,那么直接获取到的宽高值都将为0。 那么有没有什么办法可以直接获取到View的宽高值呢?当然有,参考主席的《Android开发艺术探索》,总共有四种方法可以解决上面那个问题。
1. view.post(runnable)。
我们在onStart中加入以下代码:
tv1.post(new Runnable() {
@Override
public void run() {
Log.d("tvWidth", String.valueOf(tv1.getWidth())); Log.d("tvHeight", String.valueOf(tv1.getHeight()));
}
});
我们可以看到,tv1的宽高值都被打印了出来。说明这个办法是可以获取到View的宽高值的。 这是因为view通过post可以将一个Runnable投递到消息队列的末尾,然后等待Looper调用此runnable,调用的时候View已经初始化完毕,可以获取到它的宽高值。
2 . Activity/View#onWindowFocusChanged
当Activity执行onWindowFocusChanged方法并且焦点出于获取状态的时候,View的初始化工作已经完成,此时获取View的宽高也不会有什么问题。 代码如下
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { int width = tv1.getMeasuredWidth(); int height = tv1.getMeasuredHeight(); Log.d("tv1Width", String.valueOf(width)); Log.d("tv1Height", String.valueOf(height)); } }
3 . ViewTreeObserver
使用ViewTreeObserver的回调也可以解决这个问题。 添加如下代码:
ViewTreeObserver observer = tv1.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { tv1.getViewTreeObserver().removeOnGlobalLayoutListener(this); } int width = tv1.getMeasuredWidth(); int height = tv1.getMeasuredHeight(); Log.d("tv1Width", String.valueOf(width)); Log.d("tv1Height", String.valueOf(height)); } });
在View树发生布局变化的时候,此回调会响应,此时获取View的宽高也不会有什么问题。
4 . 手动measure
通过手动执行measure方法得到View的宽高。此办法需要考虑不同的情况。 如果View的LayoutParams是MATCH_PARENT的话,那么可以直接放弃,因为子match_parnt需要获取父容器的宽高,此时子View的宽高都不能获取,获取父容器的宽高是一件不可能的事情。 如果是直接的数值单位,如dp或者px,可以如下measure:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTILY); int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXATILY); tv1.measure(widthMeasureSpec, heightMeasureSpec);
如果是wrap_content,那么使用如下代码
int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST); int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST); tv1.measure(widthMeasureSpec,heightMeasureSpec);
使用wrap_content的时候,因为我们不知道如果使用size值,使用我们传入了最大的值2^30,即1 << 30 - 1。
相关文章推荐
- statusbar 纯白色的解决方案 android:fitsSystemWindows
- JavaScript 通过native.js 调用Android原生API
- Android消息机制和多线程
- 乐学成语(3)
- 浅谈Android中MVP模式用于实际项目中的问题与优化
- android通讯录之通话记录
- 全面介绍Android Studio中Git 的使用(二)
- 全面介绍Android Studio中Git的使用(一)
- android通讯录之短信
- Andorid View工作机制(3)—measure过程 下
- Android-数据存储2(SQLite)及Android底层框架简介
- 乐学成语(2)
- 调用Android系统摄像头进行拍照以及从图库选择图片
- socket传送自定义对象
- Android开发使用Viewpager实现程序引导界面
- Android事件分发及拦截机制
- Android发版问题总结
- Android HID设备的连接
- 自定义ZXing二维码扫描界面并解决取景框拉伸等问题
- AndroidManifest.xml清单配置文件