Android Bitmap 与 Drawable
做了好几年 Android 开发,很惭愧地说,其实我也不太能分清这两个的区别与使用场景,直到今天。
本质与区别
Bitmap 本质上是一个位图数据,它只是单纯地存储一张图片,仅此而已。
Drawable 这是一个上层的绘制工具,有点类似 View
,可以调用 Canvas
进行绘制。但 View
还承担布局、测量等工作,Drawable
就轻量多了,只负责绘制。Drawable 默认没有颜色信息,甚至连大小都没有,所以记得先设置大小后再进行绘制,然后才有了像素数据。
比如:
canvas.drawBitmap(bitmap, 0f, 0f, null)
val drawable = ColorDrawable().apply { setBounds(0, 0, 200, 200) }
drawable.draw(canvas)
这个小例子体现了 Bitmap 和 Drawable 的层次/功能差异。
因为 Bitmap 与 Drawable 根本不是一个层面的东西,所以两者不能直接互转。所谓的“互转”其实是一种“生产”:
- Bitmap -> Drawable: 创建一个 Drawable,内部保存 Bitmap 的实例,在
draw()
方法中利用Canvas
把图片绘制出来。 - Drawable -> Bitmap: 创建一个 Bitmap,把 Drawable 内的图形画上去。
这就类似我们能找一个可以临摹某幅画的画家,也可以找一个画家画个画买走,但不能说「画家」和「画」可以互转。
Android ktx 库已经提供了
Drawable.toBitmap()
与Bitmap.toDrawable()
便捷函数,具体实现就是上面说的思路。
自定义 Drawable
有人说 「自定义 Drawable 没有意义,因为系统已经提供了足够多类型的 Drawable」。
其实系统也提供了许多 View,但总有一些需求是办不到的,所以不能说它没有意义。除此之外,自定义 Drawable 还可以重用。 比如不同的 View 需要显示同一个比较复杂的东西,就可以抽出来作为 Drawable。
自定义 Drawable 与自定义 View 类似,但更简单,大概结构如下:
class MeshDrawable : Drawable() {
override fun draw(canvas: Canvas) {}
override fun setAlpha(alpha: Int) {}
override fun getAlpha(): Int {}
override fun getOpacity(): Int {}
override fun setColorFilter(colorFilter: ColorFilter?) {}
override fun getColorFilter(): ColorFilter? {}
}
其中大部分方法都可以和 Paint
关联起来,除了 getOpacity()
。这个方法与 getAlpha()
不同,不用返回具体的透明度,而是指明这个 Drawable 是所有区域都不透明,还是完全透明,还是只有部分区域透明,用于与底部/前部其他图形进行颜色混合。