第四章 View的工作原理
4.1初识ViewRoot和DecorView
1)ViewRoot对应ViewRootImpl类,View的绘制流程是从ViewRoot的performTraversals方法开始的,performTraversals会依次调用performMeasure、performLayout、performDraw方法,三个方法分别完成View的measure、layout、draw方法。
2)DecorView是顶级View,通过源码可以知道,DecorView其实是一个FrameLayout。
4.2 理解MeasureSpec
1)MeasureSpec代表一个32位的int值,高两位代表SpecMode,低30位代表SpecSize。
2)SpecMode对应三类,UNSPECIFIED、EXACTLY、AT_MOST。
UNSPECIFIED:父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量状态。
EXACTLY:View的大小固定,就是SpecSize对应的值,这种模式对应于LayoutParams中的match_parent和具体数值两种模式。
AT_MOST:父容器指定了一个可用大小的SpecSize,View的大小不能大于这个值,具体值要看不同View的具体表现。这种模式对应于LayoutParams中的warp_content。
3)在View测量的时候,系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec,MeasureSpec不是唯一由LayoutParams决定的,LayoutParams需要和父容器一起才能决定View的MeasureSpec。对于DecorView,其MeasureSpec由窗口的尺寸和其自自身的LayoutParams来共同确定;对于普通View,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定。
4)当View采用固定宽/高的时候,不管父容器的MeasureSpec是什么,View的MeasureSpec都是精确模式并且其大小遵循LayoutParams中的大小。当View的宽/高是match_parent时,如果父容器是精确模式,那么View也是精确模式并且其大小是父容器的剩余空间;如果父容器是最大模式,那么View也是最大模式并且其代销不会超过父容器的剩余空间;如果View的宽/高是wrap_content时,不管父容器的模式是精确还是最大化,View的模式总是最大化并且不超过父容器的剩余空间。
View的工作流程
measure过程
1)如果View在布局中使用wrap_content,那么它的specMode是AT_MOST模式,在这种模式下,它的宽/高等于specSize,这种情况下specSize是parentSize,而parentSize是父容器中目前可以使用的大小,也就是父容器当前剩余空间的大小。
2)Activity中获得View宽高的方式:
1.onWindowFocusChanged
2.view.post(runnable)
3.ViewTreeObserver使用OnGrobalLayoutListener接口
4.手动调用View.measure()方法。
draw过程
当我们的自定义控件继承于ViewGroup并且自身不具备绘制功能时,就可以开启这个标志位从而便于系统进行后续的优化。当然,当明确知道一个ViewGroup需要通过onDraw来绘制内容时,我们需要显式地关闭WILL_NOT_DRAW这个标志位。
自定义View
当包含此View的Activity退出或者当前View被remove时,View的onDetachedFromWindow方法会被调用,和此方法对应的是onAttachedToWindow,当包含此View的Activity启动时,View的onAttachedToWindow方法会被调用。同事,当View变得不可见时我们也需要停止线程和动画,如果不及时处理这种问题,有可能会造成内存泄漏。