您的位置:首页 > 移动开发 > Android开发

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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: