Android Drawable 简析
Drawable 是开发中经常用到的一个概念,我们经常用它去设置 View 的背景,背景可以一个颜色值,也可以是一张资源图片,还可以是一个自定义的 Drawable等等。这篇文章就简单说下 Drawable 与 View 的关系,同时结合代码,简要分析一下 Drawable 如何作用于 View。
Drawable 介绍
官方介绍
A Drawable is a general abstraction for "something that can be drawn." Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Drawable class provides a generic API for dealing with an underlying visual resource that may take a variety of forms. Unlike a
View
, a Drawable does not have any facility to receive events or otherwise interact with the user.
简单翻译下:
Drawable 是 “所有可绘制东西” 的一个抽象,大多数时候,我们只需要把各种不同类型的资源作为转化为 drawable,然后 View 会帮我们把它渲染到屏幕上。Drawable 类提供了一个通用 API,用于解析转化各种可视资源到 Canvas,跟 View 不一样,Drawable 不能接受任何事件以及用户交互。
总而言之,Drawable 就是一个可绘制东西的抽象,相比 View,它更纯粹,就是用来做绘制相关事情的,它处理不了用户交互事件,也不需要处理,所有交互相关的事都是由 View 来完成,但是背景相关的事大都可以通过 Drawable 来完成。
一般的,我们要为 View 设置背景,可通过如下几种方式:
- 通过颜色为 View 设置背景
- 通过自定义的 shape 设置背景
用颜色设置背景
通过 View 的 setBackgroundColor 方法可以设置颜色为 View 的背景。
button.setBackgroundColor(Color.YELLOW);
效果如下:
用自定义的 shape 设置背景
先用 xml 自定义一个圆角空心描边矩形 shape
<shape
android:shape="rectangle">
<corners android:radius="4dp"/>
<solid android:color="#fff"/>
<stroke android:color="#ef6f06" android:width="1dp"/>
</shape>
通过代码进行设置
button.setBackgroundResource(R.drawable.bk_normal);
效果如下:
可以看到,给 View 设置背景 drawable 非常简单,具体通过如下的 API 实现背景设置:
- setBackgroundColor(@ColorInt int color)
- setBackgroundResource(@DrawableRes int resid)
- setBackground(Drawable background)
但是设置的背景 Drawable 是如何在 View 上生效的,可能很多人没去思考过这个问题,这里简单分析下。
Drawable 如何作用于 View
Drawable 是一个抽象类,这里通过它的的几个抽象方法就能大概猜得出 Drawable 如何作用于 View,下面是 Drawable 的几个抽象方法:
public abstract void draw(@NonNull Canvas canvas);
public abstract void setAlpha(@IntRange(from=0,to=255) int alpha);
public abstract void setColorFilter(@Nullable ColorFilter colorFilter);
public abstract @PixelFormat.Opacity int getOpacity();
可以看到这里有一个 draw 方法,并且参数中提供了 canvas 对象。
public abstract void draw(@NonNull Canvas canvas);
现在可以想象一下,View 通过 setBackground 方法为自己设置了一个 drawable 对象后,而 drawable 又有一个 draw 方法,那么 View 绘制自己的背景时,直接调用 drawable 对象的的 draw 方法,这个 draw 方法需要一个 canvas 对象,这里可直接把 View 的 Canvas 对象传递过去,那么 Drawable 就可以成功的把自己的绘制内容应用到 View 之上。
这个过程,相当于 View 把自己的背景绘制功能外包给了 Drawable 对象。
而且,这也是一种非常好的设计模式,View 负责测量自己大小,给自己指定位置,并绘制 View 前景 ,但是把自己的背景绘制外派给了更独立的 drawable 去做,从而做到了让自己更加轻量,现在 View 就成功的把背景绘制职责分配给了自己的 drawable 对象。
尽管上面只是想象,但事实上也确实如此。通过查看源码,在 View 中有一个私有方法 drawBackground
,它的作用就是把 drawable 绘制在 canvas 上。
/**
* Draws the background onto the specified canvas.
* @param canvas Canvas on which to draw the background
*/
private void drawBackground(Canvas canvas) {
final Drawable background = mBackground;
if (background == null) {
return;
}
setBackgroundBounds();
//省略部分代码
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if ((scrollX | scrollY) == 0) {
//调用 drawable 自己的 draw 方法,从而将绘制的功能移交到 drawable 类
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
Drawable 与 View 的关系
- View 是皮,它是一个具体的东西,看得见摸得着,因为它自己可以测量自己打消、指定自己位置,还能接受 onTouch 事件从而处理用户交互。
- Drawable 是毛,它可以不存在,因为 View 完全可以在自己的 onDraw 时机中,自己把自己绘制了,无需把绘制进行外包。
- 但是 Drawable 更专业,更独立,它提供了一整套丰富的背景 Drawable 机制,它有丰富的实现类,可以提供给 View 进行方便的背景设置,对 View 来说 drawable 提供的那些实现类开箱即用,还可以减少自己的职能,节省自己的维护开销,何乐而不为。
总结
Drawable 是一个抽象的概念,只要理解了它跟 View 的关系,其实 Drawable 的想象力会非常大。通过自定义 Drawable,可以在 Drawable 中完成各种绘制逻辑,自定义完成后,只需要让 View 调用 setBackground() 方法,把自定义的 Drawable 传递进去,这样就可以方便把自定义 Drawable 和 View 关联在一起。
之前写过一个转菊花的 Loading 效果,就是用自定义 Drawable 实现的,目前已开源在 github,感兴趣的去看看。
FlowerLoading: Android loading or progress view, just like iOS IndicatorView.
关于作者
咕咚,Android 工程师,个人博客 gudong.name
本篇文章由一文多发平台ArtiPub自动发布
Android Drawable 简析的更多相关文章
- Android MVP 简析
原地址:https://segmentfault.com/a/1190000003927200 在Android中应用MVP模式的原因与方法的简析,写的简单易懂.
- Android : SELinux 简析&修改
一 SELinux背景知识 SELinux出现之前,Linux上的安全模型叫DAC,全称是Discretionary Access Control,翻译为自主访问控制.DAC的核心思想很简单,就是: ...
- Android View 简析
基于android 4.4上源码分析: setContentView流程: getwindow() ->setContentView() -> installDecor() -> a ...
- android:installLocation简析
在Froyo(android 2.2,API Level:8)中引入了android:installLocation.通过设置该属性可以使得开发者以及用户决定程序的安装位置. android:inst ...
- Android -- ImageLoader简析
图片的内存缓存实现 Image-Loader库有一个较完整的内存缓存实现,使用者可以根据需要选择已经实现的策略,也可以定制自己项目中需要的策略. 内存缓存实现代码在memory和memory.impl ...
- Android RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- Android 启动过程简析
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
- zxing二维码扫描的流程简析(Android版)
目前市面上二维码的扫描似乎用开源google的zxing比较多,接下去以2.2版本做一个简析吧,勿喷... 下载下来后定位两个文件夹,core和android,core是一些核心的库,android是 ...
随机推荐
- HDU 1428漫步校园
漫步校园 Problem Description LL最近沉迷于AC不能自拔,每天寝室.机房两点一线.由于长时间坐在电脑边,缺乏运动.他决定充分利用每次从寝室到机房的时间,在校园里散散步.整个HDU校 ...
- Python操作三大主流数据库☝☝☝
Python操作三大主流数据库☝☝☝ Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口. Python 数据库接口支持非常多的数 ...
- ZGC gc策略及回收过程-源码分析
源码文件:/src/hotspot/share/gc/z/zDirector.cpp 一.回收策略 main入口函数: void ZDirector::run_service() { // Main ...
- F#周报2019年第42期
新闻 TypeShape的性能 .NET Core 3.0包含.NET Framework API移植项目 宣告.NET Core 3.1预览版1 .NET Core 3.1预览版1中ASP.NET ...
- [JoyOI1519] 博彩游戏
题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目背景 Bob最近迷上了一个博彩游戏…… 题目描述 这个游戏的规则是这样的:每花一块钱可以 ...
- [Luogu3932] 浮游大陆的68号岛
题目背景 大样例下发链接: https://pan.baidu.com/s/1nuVpRS1 密码: sfxg 浮游大陆的68号岛,位于浮游大陆的边境地带.平时很少有人造访. 岛上被浓厚的森林覆盖. ...
- ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
1.前言 这一篇,博主将教大家怎么去实现一个WiFi RGB彩灯. 先来一个博主已经实现功能的图片,如下: 当然,博主也拍了运行视频,请点击 传输门. 1.1 知识储备 ...
- GO基础之流程控制语句
一.if分支语句 if 布尔表达式 1 { /* 在布尔表达式 1 为 true 时执行 */ } ; a% == { fmt.Println("偶数") } if 布尔表达式 1 ...
- Spring Cloud 网关服务 zuul 二
有一点上篇文章忘了 讲述,nacos的加载优先级别最高.服务启动优先拉去配置信息.所以上一篇服务搭建我没有讲述在nacos 中心创建的配置文件 可以看到服务端口和注册中心都在配置文件中配置化 属性信息 ...
- Swagger Learing - Spring Boot 整合swagger
学习了一下swagger. 这是编写的Demo 源码 https://github.com/AmberBar/Learning/tree/master/swagger-learning/swagger ...