一:View是如何被添加到屏幕窗口的。
打开Activity,在oncreat()方法里面,调用了setContentView()方法,方法参数传入布局文件。调用流程:
setContentView()-->getWindow().setContentView()【getWindow是Window类中的方法,Window继承了抽象的PhoneWindow】--->实际调用了PhoneWindow中的setContentView()方法-->调用instalDecor()
方法,在此方法中首先调用generateDecor()方法,创建DecorView对象,其次调用了generateLayout()方法首先根据features不同初始化不同的layoutResource(基础容器)-->通过onResourceLoaded()方法把layoutResource进行解析,并添加到DecorView容器上。然后在generateLayout()方法中通过findViewByID找到R.id.conent的容器,该容器为FrameLayout,把通过setContentView()方法传递进入的布局文件解析到FrameLayout容器中。
总结:首先系统会创建一个顶层的容器DecorView,DecorView是ViewGroup继承FrameLayout,是PhoneWindow持有的一个实例,DecorView是所有应用程序的顶层View,在系统内部进行初始化,当DecorView完成初始化之后系统不根据当前应用程序的主题特性,加载一个基础容器,例如:no_action_bar,dark_action_bar。不同的主题加载的基础容器不同,但基础容器都存在R.id.content的FrameLayout的容器,我们开发者通过setContentView设置的布局文件(xml文件)就是通过解析之后加载到FrameLayout中的。
二:View的绘制流程
1:绘制入口
ActivitytThread.handleResumeActivity()--->WindowManagerImpl.addView(decorView,layoutParams)-->WindowManagerGlobal.addView(),此方法会创建出ViewRootImpl对象
2:绘制类及方法
ViewRootImpl.setView(decorView,layoutParams,parentView)将decorView与布局属性,布局进行关联--->ViewRootImpl.requestLayout()--->ViewRootImpl.scheduleTraversals()--->子线程调用doTraversals()--->performTraversals(),次方法是真正绘制的方法。
3:绘制三大步骤
测量:ViewRootImpl.performMeasure(); 布局:ViewRootImpl.performLayout(); 绘制:ViewRootImpl.performDraw();
总结:当Activity创建之后,在Activty的handlResumeActivity()方法中通过VM调用了addView方法,VM找到实现类WindowManagerImpl,调用addView()方法,addView第一个参数是顶层的DecorView,第二个参数是布局属性。接着调用WindowManagerGloabl.addView()方法,再次方法中会创建ViewRootImpl对象,调用setView()方法,将DecorView,布局属性,布局进行关联,关联成功后ViewRootImpl准备绘制,调用了ViewRootImpl的requestLyaout()方法,然后调用了schedluTraversals(),在子线程调用了doTraversals()方法,在调用了perFormTraversals(),次方法是真正真正绘制的方法。
4:详细步骤(测量)
(1)View的测量包含两部分模式+尺寸,被封装到了MeasureSpec
MeasureSpec:是一个32位int类型的值,前面2位是模式,后面30位是尺寸。是View 的测量规格 view的测量 = specMode (模式) + specSize(尺寸)。
makeMeasureSpec方法把模式和尺寸打包生成成MeasureSpec
a: 3种测量模式。 MODE_SHIFT = 30 位 MODE_MASK =0x3 <<MODE_SHIFT
UNSPECIFIED 0<<MODE_SHIFT 父容器不对View做任何限制,一般系统使用。 EXACTLY 1<<MODE_SHIFT 父容器检测view的大小,view的大小就是specSize ,布局属性 layoutParams子控件match_parent 或者固定大小。 AT_MOST 2<<MODE_SHIFT 父容器指定一个可用大小specSize,view最大不能超过这个值,布 局属性子控件 layoutParams为wrap_content
b:顶层View -------确定DecorView的MeasureSpec
DecorView的MeasureSpec由窗口大小,自身的LayoutParsms决定。
自身LayoutParsms.MATCH_PARENT:精确模式,大小为窗口大小,模式为 EXACTLY.
自身LayoutParsms.WRAP_CONTENT:最大模式,大小最大为窗口大小,模式为 AT_MOST.
固定大小:精确模式,大小自身LayoutParsms的大小,模式为 EXACTLY.
![](https://img.haomeiwen.com/i3787581/beb89d8cbf871557.png)
View测量
ViewGroup mesure()---->onMeasure(测量子控件的宽高)--->setMeasureDimesion()-->setMeasureDimesionRaw(保存自己的宽高)
View mesure()---->onMeasure()--->setMeasureDimesion()-->setMeasureDimesionRaw(保存自己的宽高)
View 的布局
ViewGroup layout(来确定自己的位置,4个点左上右下)--->onLayout(进行子View的布局)
View layout(来确定自己的位置,4个点左上右下)
View的绘制
ViewGroup
(1)绘制背景 drawBackGround(canvas)
(2)绘制自己 onDraw(canvas)
(3)绘制子View dispatchDraw(canvas)
(4)绘制前景,滚动条等装饰 onDrawForeground(canvas)
View
(1)绘制背景 drawBackGround(canvas)
(2)绘制自己 onDraw(canvas)
(3)绘制子View dispatchDraw(canvas)
(4)绘制前景,滚动条等装饰 onDrawForeground(canvas)
网友评论