一、体系
Activity -> phoneWindow ->DecorView -> 各ViewGroup等
1.DecorView(FrameLayout)包含StateView、TitileView、ContentView 等子View ,setContentView 设置的是DecorView子View。
2.Activity 托管 phoneWindow实例对象,phoneWindow管理DecorView。因此在Activity中可以getWindow().DecorView得到顶层View。
3.decorView https://blog.csdn.net/guxiao1201/article/details/41744107

    ![](https://s1.51cto.com/images/blog/201911/26/6882694717c8640b263a8b41affabac5.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

二、分类
TextView - Button EditText
ImageView - ImageButton
ProgressView
ViewGroup - map和6大布局组件 (ScrowView继承FrameLayout WebView继承AbsultLayout)
SurefaceView - videoView
ViewStub

三、绘制原理
视图绘制的起点在ViewRootImpl类的performTraversals()方法,该方法主要工作: 根据之前的状态,判定是否重新计算测试视图大小(measure)、是否重新放置视图位置(layout)、是否重新重绘视图(draw)
1、measure() 递归测量组件本身的大小
MeasureSpec是一个组合尺寸,它是一个32位bit值,高两位是尺寸模式specMode,低30位是尺寸大小值
specMode有三种: MeasureSpec.EXACTLY表示确定大小, MeasureSpec.AT_MOST表示最大大小, MeasureSpec.UNSPECIFIED不确定
int measureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); //合成
int specMode = MeasureSpec.getMode(measureSpec); //拆解
int specSize = MeasureSpec.getSize(measureSpec);
使用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高,必须保证这两个方法在onMeasure流程之后被调用才能返回有效值

2、layout() 确定组件在视图中的位置
measure操作完成后得到的是对每个View经测量过的measuredWidth和measuredHeight,layout操作完成之后得到的是对每个View进行位置分配后的mLeft、mTop、mRight、mBottom,这些值都是相对于父View来说的
使用View的getWidth()和getHeight()方法来获取View测量的宽高,必须保证这两个方法在onLayout流程之后被调用才能返回有效值。

3、draw() 根据位置和大小,将组件画出来
如果该View是一个ViewGroup,则需要递归绘制其所包含的所有子View。
View默认不会绘制任何内容,真正的绘制都需要自己在子类中实现。
默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致,但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序。

四、View常用方法
1、invalidate、postInvalidate()请求当前view重新绘制
invalidate主线程调用
postInvalidate非主线程调用

2、requestLayout:
requestLayout会直接递归调用父窗口的requestLayout,递归一直到ViewRootImpl,然后触发peformTraversals,导致onMeasure和onLayout被调用。不一定会触发OnDraw。requestLayout触发onDraw可能是因为在在layout过程中发现l,t,r,b和以前不一样,那就会触发一次invalidate,所以触发了onDraw,也可能是因为别的原因导致mDirty非空(比如在跑动画)
调用addView、setVisbility、setText方法都会触发requestLayout

3、scrollTo()、scrollBy()
scrollBy内部是调用的scrollTo ,scrollBy移动的坐标是相对当前控件的坐标地址,而scrollTo是移动当前控件的绝对地址。(正数向左或向上 负数向右或向下移动)

参考:https://www.jianshu.com/p/5ae3356014ed