View的工作原理

ViewRoot和DecorView

ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通ViewRoot来完成的,在ActivityThread中,当Activity对象被创建完毕后,会讲DecorView添加到Window中,同时会创建ViewRootImpl对讲,通过ViewRootImpl.setView方法将ViewRootImpl和DecorView关联。

View的绘制流程是从ViewRoot的performTraversals方法开始的,它经过measure,layout,draw三个过程,其中measure用来测量View的宽高,layout用来确定View在父容器中的放置位置,draw则负责将view绘制在屏幕上。

performTraversals会依次调用performMeasure、performLayout、performDraw三个方法,这三个方法分别完成顶级View的measure、layout、draw这三个过程,其中在performMeasure中会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有子元素进行measure过程,这个时候measure流程就从父容器传递到子元素了,这样就完成了一次measure过程。接着子元素会重复父容器的measure过程,如此反复就完成了整个view树的遍历,performLayout、performDraw传递流程和performMeasure是类似的,唯一不同的是performDraw的传递过程是在draw方法中通过dispatchDraw来实现的,不过这本质没有区别。

measure过程:

如果只是一个原始的View,那么通过measure->onMeasure方法就可以完成测量过程,如果是一个ViewGroup,除了完成自己的测量外,还会遍历去调用所有子元素的measure方法,各个子元素再递归调用这个过程
直接继承View的自定义控件需要重写onMeasure方法并且设置wrap_content时的自身大小,否在在布局中使用wrap_content就相当于使用match_partent

image.png

因为默认宽高等于specSize,这种情况下specSize是partentSize,也就是父容器目前可用大小

layout过程:

layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,他在onLayout中会遍历所有的子元素并调用其layout方法,在layout方法中onLayout又会被调用。layout方法确定view本身的位置,onlayout方法确定所有子元素的位置

draw过程:

  • 绘制背景background.draw(canvas)
  • 绘制自己(onDraw)
  • 绘制children(dispatchDraw)
  • 绘制装饰(onDrawForeground)
  • 绘制默认焦点突出显示(drawDefaultFocusHighlight(canvas))


    image.png

你可能感兴趣的:(View的工作原理)