MeasureSpec
MeasureSpec是一个32位值,高2位代表SpecMode,低30位代表SpecSize。
UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量状态。
EXACTLY:父容器已经检测出View所需的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
AT_MOST:父容器制定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。
顶级View(DecorView):MeasureSpec由窗口的尺寸和其自身的LayoutParams来共同确定
直接继承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的宽/高,会被回调多次。
View默认没有启用setWillNotDraw,而ViewGroup默认启用了。
尽量不要在View中使用Handler,因为View内部本身提供了post系列的方法,完全可以替代Handler的作用,除非你很明确地要使用Handler来发送消息。