一 View的添加过程
先来一张时序图:
Activity的启动过程上图描述了Activity的启动过程,简言之就是:AMS通知zygote去fork出来要启动的Activity进程,然后切换到这个Activity的进程中去执行,进程的入口是ActivityThread的main()方法,然后会调用ActivityThread的attach方法,最终会调用到Activity的attach方法中去,在Activity的attach中创建了Window(实现是PhoneWindow),然后再经过一些列调用,会回调到Activity的onCreate()中去。如果在Activity的onCreate()中调用了setContentView(),那么就会创建DecorView,DecorView会在Activity的onResume() 回调中添加到Window上并显示,这里的顺序为:先添加DecorView到Window上,再回调Activity的onResume()方法,然后才使得DecorView可见,可以看一下上面的时序图自行理解一下,这里简单的理一下主线路:
Activity.attach() -> 创建Window(PhoneWindow) -> setContentView(view) -> 创建DecorView并将view添加到DecorView 中 -> 回调onResume() -> 将DecorView添加到当前View树上来 -> 触发一次layout(布局测量绘制);
我们再来建立一下View树的概念,Android的整个UI体系是一颗多叉树,根结点是ViewRootImpl,要更新任何一个View都需要从根结点触发,大概流程如下图:
View树
每一个View(ViewGroup)都需要触发自己的requestLayout方法来更新自己,View的requestLayout方法会沿着View树向上传递到ViewRootImpl,在此过程中通过给自己添加flag的方式来标记自己需要更新,最终触发ViewRootImpl的requestLayout方法,然后ViewRootImpl触发一个performTraversals()来刷新整个View树,此过程包括measure(), layout()和draw(), 最终又沿着View树向下传递到每个子View,子View会检查向上传递时候添加的flag来触发自己的更新,这里重点就是绘制的时候坐标系的变换。
先来看一下View的继承关系和一些属性:
View的继承关系再来看一下坐标系:
未滑动 红线表示滑动后的getX和getY这里有两个概念1 View的坐标系 2 View内容的坐标系
View的坐标系:表示以View的左上角为原点的坐标系
View内容的坐标系: 表示以View的内容的开始位置的左上角为原点的坐标系,比方说:View设置了padding为5dp,那么View内容的坐标系就是View的坐标系向右和向下移动5个dp,引入内容的坐标系是为了方便绘制,只要通过canvas.translate(dx,dy),就可以移动到View内容的坐标系,从而使得绘制的时候不需要考虑View的滑动等问题,View在绘制阶段向下分发的时候,都会先调用canvas.save()保存当前状态,然后直接或间接调用canvas.translate(dx,dy)从而将当前坐标系移动到子View的坐标系,然后子View进行绘制后,再通过canvas.restore()恢复到父View的坐标系,然后父布局再分发给下一个View来进行绘制,直到绘制完毕
网友评论