Carson带你学Android:深入解析自定义View工作流程

2023-10-15 00:50

本文主要是介绍Carson带你学Android:深入解析自定义View工作流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


前言

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

Carson带你学Android自定义View文章系列:
Carson带你学Android:自定义View基础
Carson带你学Android:一文梳理自定义View工作流程
Carson带你学Android:自定义View Measure过程
Carson带你学Android:自定义View Layout过程
Carson带你学Android:自定义View Draw过程
Carson带你学Android:手把手教你写一个完整的自定义View
Carson带你学Android:Canvas类全面解析
Carson带你学Android:Path类全面解析


目录

示意图


1. 储备知识

1.1 ViewRoot

  • 定义
    连接器,对应于ViewRootImpl

  • 作用

    1. 连接WindowManagerDecorView
    2. 完成View的三大流程: measurelayoutdraw
  • 特别注意

// 在主线程中,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的关系

  • 简介

示意图

  • 之间的关系
    示意图

  • 更加详细 & 具体的介绍,请看文章:Android自定义View基础:ViewRoot、DecorView & Window的简介

1.4 自定义View基础

了解自定义View流程前,需了解一定的自定义View基础,具体请看文章:Carson带你学Android:自定义View基础


2. 绘制准备

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

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

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

  • 主要包括:DecorView创建 & 显示,具体请看文章:Android自定义View绘制前的准备:DecorView创建 & 显示

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()去获取最终的宽 / 高
  • 具体流程

示意图

示意图

  • 详细讲解
    请看文章:Carson带你学Android:自定义View Measure过程

4.2 Layout过程

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

即计算View的四个顶点位置:LeftTopRightBottom

  • 具体流程
    示意图

示意图

  • 详细讲解

请看文章:Carson带你学Android:自定义View Layout过程

4.3 Draw过程

  • 作用
    绘制View视图

  • 具体流程

示意图

示意图

  • 详细讲解
    请看文章:Carson带你学Android:自定义View Draw过程

至此,关于自定义View的工作流程讲解完毕。


5. 自定义View的步骤

步骤1:实现Measure、Layout、Draw流程

  • 从View的工作流程(measure过程、layout过程、draw过程)来看,若要实现自定义View,根据自定义View的种类不同(单一View / ViewGroup),需自定义实现不同的方法
  • 主要是:onMeasure()onLayout()onDraw(),具体如下

示意图

步骤2:自定义属性

  1. 在values目录下创建自定义属性的xml文件
  2. 在自定义View的构造方法中加载自定义XML文件 & 解析属性值
  3. 在布局文件中使用自定义属性

6. 实例讲解

结合原理 & 实现步骤,若需实现1个自定义View,请看文章:Carson带你学Android:手把手教你写一个完整的自定义View


7. 总结

  • 本文全面总结自定义View 的原理。至此,关于自定义View的绘制流程您应该非常熟悉了
  • Carson带你学Android自定义View文章系列:
    Carson带你学Android:自定义View基础
    Carson带你学Android:一文梳理自定义View工作流程
    Carson带你学Android:自定义View Measure过程
    Carson带你学Android:自定义View Layout过程
    Carson带你学Android:自定义View Draw过程
    Carson带你学Android:手把手教你写一个完整的自定义View
    Carson带你学Android:Canvas类全面解析
    Carson带你学Android:Path类全面解析

欢迎关注Carson_Ho的CSDN博客 与 公众号!

博客链接:https://carsonho.blog.csdn.net/


请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

这篇关于Carson带你学Android:深入解析自定义View工作流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/214279

相关文章

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

springboot启动流程过程

《springboot启动流程过程》SpringBoot简化了Spring框架的使用,通过创建`SpringApplication`对象,判断应用类型并设置初始化器和监听器,在`run`方法中,读取配... 目录springboot启动流程springboot程序启动入口1.创建SpringApplicat

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

在Rust中要用Struct和Enum组织数据的原因解析

《在Rust中要用Struct和Enum组织数据的原因解析》在Rust中,Struct和Enum是组织数据的核心工具,Struct用于将相关字段封装为单一实体,便于管理和扩展,Enum用于明确定义所有... 目录为什么在Rust中要用Struct和Enum组织数据?一、使用struct组织数据:将相关字段绑

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

MySQL的cpu使用率100%的问题排查流程

《MySQL的cpu使用率100%的问题排查流程》线上mysql服务器经常性出现cpu使用率100%的告警,因此本文整理一下排查该问题的常规流程,文中通过代码示例讲解的非常详细,对大家的学习或工作有一... 目录1. 确认CPU占用来源2. 实时分析mysql活动3. 分析慢查询与执行计划4. 检查索引与表