1. 在Activity中的attach方法中建立phoneWindow对象,其中phoneWindow是window的子类。
2. 一切从onCreate()中的setContentView()开始,在setContentView()之前设置一些风格,以便在建立DecorView时设置风格。
3.setContentView()方法中会建立DecorView对象,之后会调用generateLayout(),这个方法中首先根据之前设置的风格来制定风格,默认是加入一个LinearLayout的布局,其中有2个FrameLayout的布局,一个是title(子布局是TextView),另一个是id 为: android:id="@android:id/content",我们setContentView时的布局将加再这里。
4.在将DecorView addView()到window中时,addView()中创建了一个对象ViewRoot,ViewRoot其实就一个Handle,它会掉用scheduleTraversals()发送一个message(这个message被Loop取出给ViewRoot中的handleMessage里的一个方法),这个方法是就performTraversals(),也就是启动了绘画流程,这个方法里面会分别调用measure、layout、draw。
5.draw 函数:
递归的绘制整个窗口需要按顺序执行以下几个步骤:
- 绘制背景;
- 如果需要,保存画布(canvas)的层为淡入或淡出做准备;
- 绘制 View 本身的内容,通过调用 View.onDraw(canvas) 函数实现,通过这个我们应该能看出来 onDraw 函数重载的重要性,onDraw 函数中绘制线条 / 圆 / 文字等功能会调用 Canvas 中对应的功能。下面我们会 drawLine 函数为例进行说明;
- 绘制自己的孩子(通常也是一个 view 系统),通过 dispatchDraw(canvas) 实现,参看 ViewGroup.Java 中的代码可知,dispatchDraw->drawChild->child.draw(canvas) 这样的调用过程被用来保证每个子 View 的 draw 函数都被调用,通过这种递归调用从而让整个 View 树中的所有 View 的内容都得到绘制。在调用每个子 View 的 draw 函数之前,需要绘制的 View 的绘制位置是在 Canvas 通过 translate 函数调用来进行切换的,窗口中的所有 View 是共用一个 Canvas 对象
- 如果需要,绘制淡入淡出相关的内容并恢复保存的画布所在的层(layer)
- 绘制修饰的内容(例如滚动条,方法:onDrawScrollBars(canvas))