View的工作原理

三大流程

在ActivityThread中,当Activity创建完毕后,会将DecorView附加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImplDecorView建立关联。

ViewRootIml其实是DecorView的管理类。

View的绘制流程是从ViewRoot的performTraversals()方法开始的,经过measurelayoutdraw三个过程才能最终将一个View绘制出来。

measure

通过调用setMeasuredDimension决定View的宽高。

计算之后可以通过getMeasureWidthgetMeasureHeight获取测量后的结构。

measureChildren

通过遍历调用measureChild(child,widthMeasureSpec,heightMeasureSpec)方法完成所有子View的测量。

layout

用来确定子元素的位置。需要遍历子元素,调用其layout方法。

决定了View的四个顶点的坐标和实际的View的宽和高。

getWidthgetHeight才是View的最终宽高。

onDraw

  1. 绘制背景background.draw(canvas)。
  2. 绘制自己(onDraw)。
  3. 绘制children(dispatchDraw)。
  4. 绘制装饰(onDrawScrollBars)。

DecorView

DecorView作为顶级的View,包含一个竖直的LinnerLayout,内部含有标题栏和内容栏.setContentView就是把View附加到内容栏。内容栏是个FrameLayout,他的的id是content,所以是setContentView。

1
2
3
4
5
//获取content内容栏
ViewGroup content= findViewById (R.android.id.content)

//获取我们自己的顶级View
View rootView = content.getChildAt(0);

MeasureSpec

这是一个32位的int,高2位代表SpecMode,低30位代表SpecSize。

通过将SpecMode和SpecSize打包成一个int,避免过多的内存分配。

获取View的宽高

view的measure过程和Activitu生命周期不同步,所有在onCreate、onStart、onResume中都不能获取到View的宽高。

生命周期

  1. Constructors构造函数;
  2. onFinishInflate当该View及其子View从XML文件中填充完成后会被调用;
  3. onAttachedToWindow附加到窗口;
  4. onMeasure计算尺寸时调用;
  5. onSizeChanged当前view尺寸变化时调用;
  6. onLayout调用所有子view的layout方法为每一个子view确定位置;
  7. onDraw绘图时调用;
  8. onDetackedFromWindow脱离窗口时调用。