专栏名称: Carson_Ho
走在产品路上的Android研究生
目录
相关文章推荐
开发者全社区  ·  大佬总爱找空姐 ·  20 小时前  
鸿洋  ·  Android WebView ... ·  昨天  
开发者全社区  ·  陆家嘴某基金老登被曝光 ·  2 天前  
鸿洋  ·  HarmonyOS ... ·  2 天前  
开发者全社区  ·  前公司客户「相中」我当儿媳妇... ·  2 天前  
51好读  ›  专栏  ›  Carson_Ho

Android:手把手带你清晰梳理自定义View的工作全流程!

Carson_Ho  · 掘金  · android  · 2019-08-06 00:13

正文

前言

  • 自定义 View Android 开发者必须了解的基础
  • 网上有大量关于自定义 View 原理的文章,但存在一些问题: 内容不全、思路不清晰、无源码分析、简单问题复杂化等等
  • 今天,我将全面总结自定义 View 的全工作流程,我能保证这是 市面上的最全面、最清晰、最易懂的
  1. 本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题;
  2. 所以,请各位读者先记住结论,再往下继续看分析;
  3. 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读

目录

示意图


1. 储备知识

1.1 ViewRoot

  • 定义
    连接器,对应于 ViewRootImpl

  • 作用

    1. 连接 WindowManager DecorView
    2. 完成 View 的三大流程: measure layout draw
  • 特别注意

// 在主线程中,Activity对象被创建后:
// 1. 自动将DecorView添加到Window中 & 创建ViewRootImpll对象
root = new ViewRootImpl(view.getContent(),display);

// 3. 将ViewRootImpll对象与DecorView建立关联
root.setView(view,wparams,panelParentView)

1.2 DecorView

  • 定义:顶层 View

Android 视图树的根节点;同时也是 FrameLayout 的子类

  • 作用:显示 & 加载布局

View 层的事件都先经过 DecorView ,再传递到 View

  • 特别说明
    内含1个竖直方向的 LinearLayout ,分为2部分:上 = 标题栏 (titlebar) 、下 = 内容栏 (content)

示意图

Activity 中通过 setContentView() 所设置的布局文件其实是被加到内容栏之中的,成为其唯一子View = id为content的 FrameLayout

// 在代码中可通过content得到对应加载的布局

// 1. 得到content
ViewGroup content = (ViewGroup)findViewById(android.R.id.content);
// 2. 得到设置的View
ViewGroup rootView = (ViewGroup) content.getChildAt(0);

1.3 Window、Activity、DecorView 与 ViewRoot的关系

  • 简介

示意图

1.4 自定义View基础

了解自定义View流程前,需了解一定的自定义View基础,具体请看文章: (1)自定义View基础 - 最易懂的自定义View原理系列


2. 绘制准备

  • 回忆上图,可看出最后1步 = 绘制
    示意图

  • 但在绘制前,系统会有一些绘制准备,即前面几个步骤:创建 PhoneWindow 类、 DecorView 类、 ViewRootmpl 类等

故,下面我会先将绘制前的准备,再开始讲绘制流程


3. 绘制流程概述

  • 从上可知, View 的绘制流程开始于: ViewRootImpl 对象的 performTraversals()
  • 源码分析
/**
  * 源码分析:ViewRootImpl.performTraversals()
  */
  private void performTraversals() {

  		// 1. 执行measure流程
        // 内部会调用performMeasure()
        measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);

        // 2. 执行layout流程
        performLayout(lp, mWidth, mHeight);

        // 3. 执行draw流程
        performDraw();
    }
  • 从上面的 performTraversals() 可知: View 的绘制流程从顶级 View(DecorView) ViewGroup 开始,一层一层从 ViewGroup 至子 View 遍历测绘

即:自上而下遍历、由父视图到子视图、每一个 ViewGroup 负责测绘它所有的子视图,而最底层的 View 会负责测绘自身

示意图

  • 绘制的流程 = measure 过程、 layout 过程、 draw 过程,具体如下

示意图

示意图

下面,我将详细讲解 View 绘制的三大流程: measure 过程、 layout 过程、 draw 过程


4. 详细介绍

4.1 Measure 过程

  • 作用
    测量 View 的宽 / 高
  1. 在某些情况下,需要多次测量 (measure) 才能确定 View 最终的宽/高;
  2. 该情况下, measure 过程后得到的宽 / 高可能不准确;
  3. 此处建议:在 layout 过程中 onLayout() 去获取最终的宽 / 高
  • 具体流程

示意图

示意图

4.2 Layout过程

  • 作用
    计算视图 (View) 的位置

即计算 View 的四个顶点位置: Left Top Right Bottom

  • 具体流程
    示意图

示意图

  • 详细讲解

请看文章: 自定义View Layout过程 - 最易懂的自定义View原理系列(3)







请到「今天看啥」查看全文