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体系(四)从源 ...
随机推荐
- python 2.x 中print >> sys.out ,print 与sys.out.write()的关系
print 会调用 sys.stdout 的 write 方法 以下两行在事实上等价: sys.stdout.write('hello,python'+'\n') print 'hello,pytho ...
- vCenter Server Appliance(VCSA )6.7部署指南
目录 简介 环境准备 开始安装 第一阶段安装 第二阶段安装 使用 简介 早期的VCSA支持 SUSE 和 Windows,不太懂SUSE,也不想用Windows 而在2018年4月17日VCSA 6. ...
- Centos 6、7 禁止密码验证登陆
Centos 6.7 禁止密码验证登陆 安全方面的考虑,秘钥对验证登陆相对密码验证要更安全 修改 /etc/ssh/sshd_config 配置文件 该配置文件中,只需要修改一个参数 Password ...
- 【集合系列】- 深入浅出分析HashMap
一.摘要 在集合系列的第一章,咱们了解到,Map的实现类有HashMap.LinkedHashMap.TreeMap.IdentityHashMap.WeakHashMap.Hashtable.Pro ...
- RestSharp Simple REST and HTTP API Client for .NET
var client = new RestClient("http://example.com"); // client.Authenticator = new HttpBasic ...
- MySql数据基础之数据表操作
MySql数据库中主要利用多个数据表进行数据的存储,我们可以将数据表理解成一个Excel表格,Excel表格的第一列可以将它看为id列,主要任务是数据表中数据的唯一标识,不能重复.不能为空.如果将数据 ...
- SI522和RC522/ZS3801/FM17520的区别
小编最近在测试一颗新的芯片,是国内知名厂家中科微研发的,主打超低功耗的厂家. 经过测试和比较小编发现 相对于MFRC522,SI522可以完全替换,不需要做任何更改,同时接受模式下功耗低10mA左右, ...
- Redux和Context对比
Redux和Context对比 如果项目体量较小,只是需要一个公共的store存储state,而不讲究使用action来管理state,那context完全可以胜任.反之,则是redux的优点. co ...
- CSU-2018
The gaming company Sandstorm is developing an online two player game. You have been asked to impleme ...
- 【Taro】363- 玩转 Taro 跨端之 flex 布局篇
Taro 是一套遵循 React 语法规范的跨平台开发解决方案,但是目前当我们使用 Taro 的时候,在不同平台上的开发体验还有不一致的地方,所以我们也都期待有一套跨平台统一的解决方案,能够以最小差异 ...