Android UI 绘制流程及原理

View添加到窗口中的流程

  1. 创建 DecorView,顶层容器,继承于 FrameLayout。
  2. 根据主题不同,创建不同的基础容器ViewGroup(如: R.layout.screen_simple,是一个线性布局),并添加到 decorView 中。
  3. 基础容器中,有一个ID为 Window.ID_ANDROID_CONTENT(com.android.internal.R.id.content)的FrameLayout布局容器,这个容器就是contentView。开发者调用的 setContentView 方法,就是将自定义的容器追加到 contentView 中。

类图
在这里插入图片描述

  • Window是一个抽象类,定义了绘制窗口的API
  • PhoneWindow是Window具体实现类,该类内部包含DecorView对象。DecorView是所有应用窗口(Activity)的根View,DecorView是PhoneView的内部类,是FrameLayout的子类。

View的绘制流程

  1. 绘制入口
ActivityThread.handlerResumeActivity 
--> WidowManagerImpl.addView(decorView, layoutParams)
--> WindowManagerGlobal.addView()
  1. 绘制的类和方法
ViewRootImpl.setVIew(decorView, layoutParams, parentView)
-->ViewRootImpl.requestLayout()
-->scheduleTraversals() --> doTraversals() --> performTravesals()
  1. 三步骤
ViewRootImpl.performMeasure //测量 
ViewRootImpl.performLayout // 布局
ViewRootImpl.performDraw // 绘制

测量

测量View = 模式 + 尺寸 -> MeasureSpec 32int值
模式: 
    EXACTLY : 精确
    AT_MOST : 最大
    UNSPECIFIED : 
    
MeasureSpec = SpecMode(2) + SpecSize(30)
ViewGroup 容器测量 : measure  -> onMeausre(测量子控件的宽高) -> setMeasuredDimension() -> setMeasuredDimensionRaw(保存自己的宽高)
View measure : measure -> onMeasure(仅测量自己) -> setMeasuredDimension() -> setMeasuredDimensionRaw(保存自己的宽高)

布局

ViewGroup 是一个容器

  1. 调用 view.layout 确定自身的位置,即mLeft,mTop,mRirht,mBottom
  2. 如果是 ViewGroup 类型(容器类型),需要调用 onLayout 确定子 View 的位置(递归调用)

绘制

  1. 绘制背景 :drawBackground(canvas)
  2. 绘制自己 :onDraw(canvas)
  3. 绘制子VIew (如果是ViewGroup):dispatchDraw(canvas)
  4. 绘制前景,滚动条等装饰 :onDrawForeground(canvas)

自定义VIew需要重写的方法

onMeasue() -> onLayout(容器) -> [onDraw]

版权声明:本文为itsjustforyou原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。