前言
- 自定义View 是 Android 开发者必须了解的基础
- 网上有大量关于自定义View 原理的文章,但存在一些问题:内容不全、思路不清晰、无源码分析、简单问题复杂化等等
- 今天,我将全面总结自定义View 的全工作流程,我能保证这是市面上的最全面、最清晰、最易懂的
- 本文秉着“结论先行、详细分析在后”的原则,即先让大家感性认识,再通过理性分析从而理解问题;
- 所以,请各位读者先记住结论,再往下继续看分析;
- 文章较长,阅读需要较长时间,建议收藏等充足时间再进行阅读
目录
1. 储备知识
1.1 ViewRoot
- 定义
- 连接器,对应于ViewRootImpl类
- 作用
- 连接WindowManager 和 DecorView
- 完成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
即 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基础,具体请看文章:(1)自定义View基础 - 最易懂的自定义View原理系列
2. 绘制准备
-
- 但在绘制前,系统会有一些绘制准备,即前面几个步骤:创建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的宽 / 高
- 在某些情况下,需要多次测量(measure)才能确定View最终的宽/高;
- 该情况下,measure过程后得到的宽 / 高可能不准确;
- 此处建议:在layout过程中onLayout()去获取最终的宽 / 高
- 具体流程
- 详细讲解
- 请看文章:自定义View Measure过程 - 最易懂的自定义View原理系列(2)
4.2 Layout过程
即计算View的四个顶点位置:Left、Top、Right 和 Bottom
请看文章:自定义View Layout过程 - 最易懂的自定义View原理系列(3)
4.3 Draw过程
- 详细讲解
- 请看文章:(4)自定义View Draw过程- 最易懂的自定义View原理系列
至此,关于自定义View的工作流程讲解完毕。
5. 自定义View的步骤
步骤1:实现Measure、Layout、Draw流程
- 从View的工作流程(measure过程、layout过程、draw过程)来看,若要实现自定义View,根据自定义View的种类不同(单一View / ViewGroup),需自定义实现不同的方法
- 主要是:onMeasure()、onLayout()、onDraw(),具体如下
步骤2:自定义属性
- 在values目录下创建自定义属性的xml文件
- 在自定义View的构造方法中加载自定义XML文件 & 解析属性值
- 在布局文件中使用自定义属性
6. 实例讲解
结合原理 & 实现步骤,若需实现1个自定义View,请看文章:手把手教你写一个完整的自定义View
7. 总结
- 本文全面总结自定义View 的原理。至此,关于自定义View的绘制流程您应该非常熟悉了
- 接下来我将继续对自定义View的应用进行讲解,有兴趣的可以继续关注Carson_Ho的安卓开发笔记
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。