android view的工作原理(一)
前言:
在界面上Android 提供一套GUI库,里面有很多控件,但是很多时候我们并不满足于系统系统的控件,造成应用界面的同类化比较严重,所以我们需要自定义view,可以实现不同的效果,为了更好的自定义view.还需要掌握View的底层工作原理。例如:view的测量流程。布局流程以及绘制流程,这样我们就能定义自己想要的效果
自定义view有几种固定的类型的。有的直接继承自view和viewGroup.有的选择继承现有的系统控件,
1.viewRoot和DecorView
viewRoot对应viewRootImpl类,它是连接windowManager和decorView的纽带,当Activity对象被创建,会将DecorViewt添加到window中,并创建viewRootImpl对象,
并将viewRootImpl和decorView建立连接;
View的绘制流程是从viewRoot的preformTraversals方法开始,经过measure,layout,draw 三个过程最终将一个view绘制出来。
大致画一下流程图(看图说话):
preformTraversals 的流程图
根据上图所描述的:performTraversals 会一次调用performMesasure,performLayout,和performDrawa,这三个方法完成了顶级view的mesaure,layout,draw流程,其中在performMeasure中回调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器传递到子元素中,完成了一次measure过程,接着子元素会重复父容器的measure过程,完成整个view树的遍历。同理,perfromLayout和perfromDraw的传递流程是类似的,唯一不同的是perfromDraw传递过程在draw方法中通过dispatchDraw来实现,
Measure过程决定view的宽高,measure完成后,可以通过getMeasuredWidth和getMesauredHeight获取到view的宽高,
Draw过程决定了View的显示,只有draw方法完成后内容才能呈现在屏幕上。
2)DecorView(顶级视图),内部包含了一个竖直方向的LinearLayout,在这个linearLayout有上下两个部分,上边是标题栏,下边是内容栏,同时,通过源码我们可以知道,DecorView其实是一个frameLayout,view事件都先经过DecorView,然后传递到我们的View;(画图更清晰)
顶级View:DecorView的结构
2.自定义view的重要东西(MeasureSpec)
1) MeasureSpec在很大程度上决定了View的尺寸规格。这个过程受父容器的影响,在测量过程中,系统会将view的layoutParmas根据父容器所施加的规格转换为MeasureSpec,然后根据这个MesureSpec进行测量view的宽高。
2) MesaureSpec 是什么?
MeasureSpec 代表的是一个32位的int值,高两位代表SpecMode(测量模式),低20位代表SpecSize(测量大小);
MeasureSpec通过将SpecMode和SpecSize打包成一个int值,避免过对的对象内存分配。一组SpecMode和specSize可以打包为一个MeausreSpec,也可以将MeasureSpec进行解包的形式得到原始的SpecMode和SpecSize,
3)SpecMode的三个类,
1.UNSPECIFIED
父容器不对view有任何限制,要多大有多大,常用于系统内部,表示一种测量状态
2.EXACTLY
父容器已经检测出View的所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值,(match_parent)
3.AT_MOST
父容器指定一个可用的大小specSize. View的大小不能大于这个值,(wrap_content)
3.MeasureSpec和LayoutParams的对应关系
正常情况下我们使用view指定的MesaureSpec来对view进行测量,但是我们可以给View设置LayoutParams,在view测量的时候,系统会将layoutParams在父容器的约束下转换为对应的MeausreSpec。
对于DecorView,其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定,
对于普通view,其MeasureSpec由父容器的MeasureSpec和自身的layoutParams来共同决定的。
通过如下代码展示DecorView的MeasureSpec的创建过程:
getRootMeasureSpec的方法实现:
通过上述代码:DecorView的MeasureSpec的产生过程很明确了,具体来说遵守如下规则,根据LayoutParams中的宽高参数划分:
- LayoutParams.MATCH_PARENT:精确模式,大小就是窗口的大小。
- LayoutParams.WRAP_CONTENT : 最大模式,大小不定,但是不能超过窗口的大小;
- 固定大小(比如100dp):精确模式,大小为layoutParams中指定的大小;
- 通过表格的形式展现view的MeasureSpec的创建规则: