MeasureSpec

2016-06-11  本文已影响68人  2015哈哈哈

MeasureSpec是一个32位值,高2位代表SpecMode,低30位代表SpecSize。

SpecMode有3类

UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量状态。

EXACTLY:父容器已经检测出View所需的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。

AT_MOST:父容器制定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。

MeasureSpec转换过程

顶级View(DecorView):MeasureSpec由窗口的尺寸和其自身的LayoutParams来共同确定

普通View:MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定

MeasureSpec一旦确定,onMeasure中就可以确定View的测量宽/高。

直接继承View的自定义控件需要重写onMeasure方法并设置wrap_content时自身大小,否则在布局中使用wrap_content就相当于使用match_parent。

如果想在Activity一启动的时候就做一件任务,但这一任务需要获取某个View的宽/高,由于View的measure过程和Activity的生命周期方法不是同步执行的,因此无法保证Activity执行了onCreate、onStart、onResume时某个View已经测量完毕了,那么获得的宽/高就是0。有以下4种方法可以解决这个问题。

1.Activity/View#onWindowFocusChanged:此方法会被调用多次,当Activity的window得到或失去焦点时均会被调用一次。

2.view.post(runnable):通过post可以将一个runnable投递到消息队列尾部,等待Looper调用此runnable的时候,View已经初始化好了,在run方法体中获取宽/高。

3.ViewTreeObserver:使用ViewTreeObserver的众多回调都可以实现。比如使用OnGlobalLayoutListener接口,当View树状态发生改变或者View树内部的View的可见性发生改变时,onGlobalLayout会被回调,可在这里获取View的宽/高,会被回调多次。

4.view.measure:根据View的LayoutParams的类型来分别处理,较复杂。

View默认没有启用setWillNotDraw,而ViewGroup默认启用了。

自定义View

尽量不要在View中使用Handler,因为View内部本身提供了post系列的方法,完全可以替代Handler的作用,除非你很明确地要使用Handler来发送消息。

View如果有现成或者动画需要停止时,那么onDetachedFromWindow是一个很好的时机。

参见:当包含此View的Activity退出或者当前View被remove时,View的onDetachedFromWindow方法会被调用,和此方法对应的是onAttachedToWindow方法会被调用。同时,当View变得不可见时我们也需要停止线程和动画,如果不及时处理这种问题,有可能会造成内存泄露。

上一篇下一篇

猜你喜欢

热点阅读