自定义View入门——NO.2
自定义View的View绘制流程
在ActivityThread类中
ActivityClientRecord不为null,经一系列判断,调用 wm.addView(decor, l);
将decorView加载到WindowManager
Window类中创建WindowManager
跳转到WindowManagerImpl,View的绘制流程才开始。
其调用的是WindowManagerImpl中的addView(),
再在其中调用WindowManagerGlobal的addView()
ViewRootImpl是最外层布局,DecorView嵌套其中。
再在其中调用ViewRootImpl的setView()
再在其中调用requestLayout()
再在其中调用scheduleTraversals()
再在其中调用mTraversalRunnable
再在其中调用doTraversal()
再在其中调用performTraversals()
接下来的源码要根据xml中的布局来查看,以LinearLayout为例
测量模式和大小是由父布局和自己决定的。
此时,都会调用setMeasuredDimension(); 这个时候我们布局才真正指定宽度measuredWidth和高度measuredHeight。
接着执行ViewGroup的onMeasure(),指定自己的宽高(需要不断叠加子View的高度,marign,padding)。
View绘制流程measure方法总结
第一步performMeasure():用于指定和测量布局中所有控件的宽高。对于ViewGroup,先去测量子控件,根据子控件的宽高来计算和指定自己的宽高;对于View,它的宽高是由自己和父布局决定的。
第二步performLayout():用于摆放子布局或控件。通过for循环所有子View,调用childLayout()。
以LinearLayout为例
第三步performDraw():绘制所有View。对于ViewGroup,首先绘制自己的背景,然后通过for循环绘制子View的draw()方法;对于View,绘制自己的背景,绘制自己显示的内容(文字,图片,背景等)。
画背景
画自己 画子View 不断循环调用子View的draw()
该源码使用了模板设计模式。
思考问题:
1.如果想要获取View的高度,前提肯定需要调用测量方法,测量完毕后才能获取宽高。
2.View的绘制流程是在onResume()之后才开始(Activity启动流程源码)。
3.addView,setVisibility等等会调用requestLayout(),重走View绘制流程。
4.优化的时候,要根据源码来优化。