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体系(四)从源 ...
随机推荐
- HTML5的一些验证挺方便的
一些基本的验证都可以很简单的实现,节省了很多繁琐的步骤.
- MySQL 库、表、记录、相关操作(2)
库.表.记录.相关操作(2) 字段操作 create table tf1( id int primary key auto_increment, x int, y int ); # 修改 alter ...
- 配置防盗链、访问控制Directory和FilesMatch
5月31日任务 课程内容: 11.25 配置防盗链11.26 访问控制Directory11.27 访问控制FilesMatch扩展几种限制ip的方法 http://ask.apelearn.com/ ...
- 阿里巴巴主导的“华山版《Java 开发手册》”简介
1."83行代码计划"项目介绍(转自github): 2018年9月22日,在2018杭州云栖大会上,召开<码出高效:Java 开发手册>新书发布会,并宣布将图书所有收 ...
- Spring Cloud第六篇 | Hystrix仪表盘监控Hystrix Dashboard
本文是Spring Cloud专栏的第六篇文章,了解前五篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cloud ...
- es6 babel 安装以及使用
1,安装好node(需要使用npm包管理工具) 2,在本地项目路径下npm init,格式化成功后会在项目下生成一个配置文件package.json 3,本地安装bable npm install - ...
- mac 安装 XX-Net-3.12.11
目录 一 下载xx-net稳定版 二 使用Chrome浏览器 三 开启IPv6 mac禁用SIP机制 SIP 步骤 其他 附完整的csrutil命令 一 下载xx-net稳定版 github稳定版-X ...
- 2018 ACM/ICPC 南京 I题 Magic Potion
题解:最大流板题:增加两个源点,一个汇点.第一个源点到第二个源点连边,权为K,然后第一个源点再连其他点(英雄点)边权各为1,然后英雄和怪物之间按照所给连边(边权为1). 每个怪物连终点,边权为1: 参 ...
- ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
前言 IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用.IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOpti ...
- 使用iCamera 测试AR0331 300w高分辨率摄像头小结
使用iCamera 测试AR0331 300w高分辨率摄像头小结 先看下sensor特性 分辨率最高可达:2048*1536=300w像素 1080p帧率最高可达60fps 本次使用usb2,帧率14 ...