View的绘制流程概要

1、View的绘制流程是从ViewRootImpl.java的requestLayout()方法开始的,而ViewRootImpl.java的对象是在WindowManagerGlobals.java的addView()方法里面创建的,与之同时创建的还有Window.java的实现类PhoneWindow.java的对象,并将DecorView添加到PhoneWindow里面去,而且我们从源码角度分析还可以知道ViewRootImpl.java的对象是Activity在调用其生命周期的onResume()方法之后创建的。这样WindowManagerGlobals.java的addView()方法成功的将Wind、PhoneWindow、DecorView、Activity四者关联起来了。

2、在ViewRootImpl.java里面的requestLayout()方法中,调用了performTraversale()方法执行遍历View,而performTraversale()方法里面有一次调用了performMeasure()、performLayout()、performDraw()、方法,这三个方法分别对应 View.java的三大绘制流程:onMeasure()测量、onLayout()布局、onDraw()绘制。

3、首先performMeasure()方法会调用我们布局文件中的根布局ViewGroup的measure()方法——onMeasure()方法,但是ViewGroup的onMeasure()方法是一个抽象方法,具体由他的子View如FramLayout、LinearLayout、RelativeLayout去实现。但是他提供了measureChildren()方法、这个方法会循环遍历ViewGroup的子类,每循环发现一个子View,就调用measureChild()方法去测量,然后调用getChildMeasureSpec()方法结合该子View的LayoutParams参数和他的父View的MeasureSpec得到该子View的MeasureSpec参数。然后再调用子View的onMeasure()方法完成对自身的测量,完成自身测量这一步最关键的方法是setMeasureDemension()方法,该方法接收两个参数——getDefaultSize()方法的返回值,他根据前面测得的MeasureSpec参数获取到对应的width和height参数,完成测量。

4、接下来是performlayout ()方法也就是布局流程。该方法会调用其父类View的layout()方法来完成布局,该方法接收4个参数:left、top、right、bottom,也就是一个View的四个顶点位置坐标,然后调用本View的setFrame()方法设置自身的坐标位置,然后调用setChildFrame()方法,循环处理各个子View,完成子View的布局。

5、再接下来便是performDraw()方法,即绘制,它先是调用我们根布局ViewGroup的onDraw()方法,该方法里面会依次调用backGround.Draw()方法绘制自己的背景,然后调用onDraw()方法绘制自身,接着调用dispatchDraw()方法绘制各个子View,最后是调用onDrawScrollBar()方法绘制装饰信息,至此View走完一个完整的绘制流程。

6、我们这里要重点关注一个对象:MeasureSpec,他是一个32位的整型数据,高2位表示SpecMod,低30位表示SpecSize,SpecMod有三种状态:一是AT_MOST,开发中对应wrap_content;二是EXACTLY,开发中对应match_parent或者具体的数值;三是UNSPECIFIED,对应于系统级别的处理模式,应用层用的较少。各级View中,DecorView的大小由其LayoutParams参数确定,其他的子View有自身的LayoutParams参数和父View的MeasureSpec参数共同确定。ViewGroup中子View的MeasureSpec参数是通过getChildMeasureSpec()方法来获取的。

原创文章 118 获赞 149 访问量 9万+

猜你喜欢

转载自blog.csdn.net/haoyuegongzi/article/details/105816178