Android组件体系之视图绘制
一、View组件
View组件有几个重要的方法需要关注,也是自定义View经常需要重写的方法。
1、measure
作用是测量View组件的尺寸。对应的方法是onMeasure,测量View的宽和高。View和 ViewGroup都有measure方法,但ViewGroup除了测量自身尺寸,还要遍历地调用子元素的measure方法。
2、layout
用于确定布局位置。对应的方法是layout、onLayout,用于确定元素的位置,ViewGroup中的layout方法用来确定子元素的位置。
3、draw
作用是绘制内容背景,包括View的内容、子View的内容和背景。具体方法包括:drawBackground、onDraw、ViewGroup.dispatchDraw。
这个方法有个关键的入参也是唯一的入参:Canvas。其在native层有个对应的画布组件SkCanvas,该组件内部封装的SkBitmap实现了类似画纸的功能。
在Android系统中,View.draw的部分实现如下:
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) {
long logTime = System.currentTimeMillis();
onDraw(canvas);
}
...
// Step 4, draw the children
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
其中绘制背景的实现,是通过Drawable类型的变量mBackground也就是背景图来完成的。View中的onDraw是个空方法,但在具体的View组件例如ImageView中,都会有对应的扩展实现。
这里的绘制,主体功能通常是Drawable和Canvas,后者处理绘制区域、矩阵变换等工作,前者根据组件功能,实现具体绘制操作,例如BitmapDrawable中的draw方法,最终是通过Paint画笔组件和Canvas的drawBitmap方法实现绘制操作的。
对于自定义视图组件,通常需要重写onDraw方法,并在该方法中调用Canvas的drawXXX例如drawBitmap、drawText等方法来实现预期的效果,如果涉及到几何变换,还可能会用到Matrix组件。
二、Canvas组件
作为绘制处理中的画布组件,Canvas提供了裁剪区域/路径和多种图形/图像绘制功能,对应的方法有:
- clipRect、clipPath、clipRegion;
- drawBitmap、drawTex、drawLine;
具体实现都是在native层完成的,涉及SkiaCanvas、SkCanvas。
public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
checkValidClipOp(op);
return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
}
在framework层的android_graphics_Canvas.cpp中,有对应实现:
static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
jfloat r, jfloat b, jint opHandle) {
bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
opHandleToClipOp(opHandle));
return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}
该方法会调用到SkiaCanvas.cpp中的实现,这里先不展开分析。
三、融合与思考
1、Activity、Window和View之间关系
1)Window和PhoneWindow
PhoneWindow类,派生于Window,是连接Activity跟View的桥梁,所有Activity对View的操作都需要借助它。
2)Activity和Window
在Activity启动过程中,系统会调用attach方法,并创建PhoneWindow实例;之后,在具体Activity的onCreate函数中,通常都会调用setContentView方法,进而调用PhoneWindow的setContentView方法设置DecorView。
3)Window和View
Window通过WindowManagerImp类型的成员变量mWindowManager操作View。WindowManagerImpl是WindowManager接口的具体实现,该类通过WindowManagerGlobal完成addView、removeView、updateViewLayout这三个方法。
进一步地,PhoneWindow的成员变量DecorView,可以通过getViewRootImpl方法获取ViewRoot实例。与之对应的ViewRootImpl类,有个IWindowSession类型的成员变量mWindowSession,能够访问WMS。
小结:PhoneWindow类,是连接Activity跟View的桥梁;而ViewRootImpl是 View 和 WindowMangerService之间的桥梁。
(相关完整且成体系的文章,可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)
Android组件体系之视图绘制的更多相关文章
- Android组件体系之BroadcastReceiver小结
1.常见分类 BroadCastReceiver,按注册方式可以分为静态广播接收器和动态广播接收器. 静态广播接收器:不受程序是否启动的约束,当应用程序关闭之后,还是可以接收到广播(一般广 ...
- Android组件体系之ContentProvider使用注意事项
1.数据访问机制 客户端/调用者通过getContentResolver调用,由ActivityThread.AMS获取到ContentProvider的代理,再通过这个代理对象调用服务端的实现(也即 ...
- Android组件体系之Service解析
一.调用方式 1.启动服务 只启动一个服务,不进行通信,包括startService.startForegroundService两种调用方式.第二种方式适用于后台应用启动前台服务,在启动 ...
- Android组件体系之Activity启动模式解析
本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity ...
- Android View体系(一)视图坐标系
前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件,在这个系列中我会陆续讲到View坐标系.View的滑动.View的事件分发等文章来逐步介绍Android V ...
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/16330267 在上一篇文章中,我带着大家一起剖析了一下LayoutInflater ...
- 2015最流行的Android组件、工具、框架大全
Android 是目前最流行的移动操作系统之一. 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生了一大批的优秀的组件. 本文试图将目前流行的组件收集起来以 ...
- 最流行的android组件大全
目录 [−] 工具和教程 UI组件 类库 游戏引擎 Android HTML5应用 Android 是目前最流行的移动操作系统(还需要加之一吗?). 随着新版本的不断发布, Android的功能也日益 ...
- Android View体系(八)从源代码解析View的layout和draw流程
相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...
随机推荐
- 4k图片爬取+中文乱码
4k图片爬取+中文乱码 此案例有三种乱码解决方法,推荐第一种 4k图片爬取其实和普通图片爬取的过程是没有本质区别的 import requests import os from lxml import ...
- swiper实现一个好看的轮播图
轮播是我们在编写页面中经常遇到的模块,所以网上也会有各种有有关轮播图的插件.今天忽然间看到了swiper上一个高颜值的轮播功能,顺便做一下分享. 首先页面在head内要先引用 swiper的css 和 ...
- Spring Cloud第三篇 | 搭建高可用Eureka注册中心
本文是Spring Cloud专栏的第三篇文章,了解前两篇文章内容有助于更好的理解后面文章: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring ...
- 《Windows内核安全与驱动开发》 2.3 重要的数据结构
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 2.3 重要的数据结构 一.驱动对象 Windows内核采用__的编程方式 ...
- luogu P2783 有机化学之神偶尔会做作弊 |Tarjan+LCA
题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. "第1354题怎么做"&l ...
- 压缩感知重构算法之IHT算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- Java修炼——面向对象的三大特征_多态_多态的三个必要条件
多态指的是同一个方法调用,由于对象不同可能会有不同的行为,现实生活中,同一个方法,具体实现会完全不同. 多态的要点: 1.多态是方法的多态,不是属性的多态(多态与属性无关) 2.多态的存在有三个必要条 ...
- 声明式服务调用Feign
什么是 Feign Feign 是种声明式.模板化的 HTTP 客户端(仅在 consumer 中使用). 什么是声明式,有什么作用,解决什么问题? 声明式调用就像调用本地方法一样调用远程方法;无 ...
- 字典dict的深入学习(item() / items() 一致的)
字典Dict的跟进学习: 一. items()方法的遍历:items()方法把字典中每对key和value组成一个元组,并把这些元组放在列表中返回. dict = {"name" ...
- CodeForces-Round235D
链接:http://codeforces.com/contest/401/problem/D 题意:给出一个数字num和m,问通过重新排列num中的各位数字中有多少个数(mod m)=0,直接枚举 ...