Android View工作机制(4)— 我们该什么时候获取View的高宽?

来源:互联网 发布:java注释的作用 编辑:程序博客网 时间:2024/05/05 00:09
通过前面三篇总结,我们对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。

1 0
原创粉丝点击