View添加到窗口中的流程
- 创建 DecorView,顶层容器,继承于 FrameLayout。
- 根据主题不同,创建不同的基础容器ViewGroup(如: R.layout.screen_simple,是一个线性布局),并添加到 decorView 中。
- 基础容器中,有一个ID为 Window.ID_ANDROID_CONTENT(com.android.internal.R.id.content)的FrameLayout布局容器,这个容器就是contentView。开发者调用的 setContentView 方法,就是将自定义的容器追加到 contentView 中。
类图
- Window是一个抽象类,定义了绘制窗口的API
- PhoneWindow是Window具体实现类,该类内部包含DecorView对象。DecorView是所有应用窗口(Activity)的根View,DecorView是PhoneView的内部类,是FrameLayout的子类。
View的绘制流程
- 绘制入口
ActivityThread.handlerResumeActivity
--> WidowManagerImpl.addView(decorView, layoutParams)
--> WindowManagerGlobal.addView()
- 绘制的类和方法
ViewRootImpl.setVIew(decorView, layoutParams, parentView)
-->ViewRootImpl.requestLayout()
-->scheduleTraversals() --> doTraversals() --> performTravesals()
- 三步骤
ViewRootImpl.performMeasure
ViewRootImpl.performLayout
ViewRootImpl.performDraw
测量
测量View = 模式 + 尺寸 -> MeasureSpec 32位int值
模式:
EXACTLY : 精确
AT_MOST : 最大
UNSPECIFIED :
MeasureSpec = SpecMode(前2位) + SpecSize(后30位)
ViewGroup 容器测量 : measure -> onMeausre(测量子控件的宽高) -> setMeasuredDimension() -> setMeasuredDimensionRaw(保存自己的宽高)
View measure : measure -> onMeasure(仅测量自己) -> setMeasuredDimension() -> setMeasuredDimensionRaw(保存自己的宽高)
布局
ViewGroup 是一个容器
- 调用 view.layout 确定自身的位置,即mLeft,mTop,mRirht,mBottom
- 如果是 ViewGroup 类型(容器类型),需要调用 onLayout 确定子 View 的位置(递归调用)
绘制
- 绘制背景 :drawBackground(canvas)
- 绘制自己 :onDraw(canvas)
- 绘制子VIew (如果是ViewGroup):dispatchDraw(canvas)
- 绘制前景,滚动条等装饰 :onDrawForeground(canvas)
自定义VIew需要重写的方法
onMeasue() -> onLayout(容器) -> [onDraw]
|