一、Bitmap和Drawable的含义
Bitmap中文解释为位图,而本质上Bitmap是图片像素点的集合。
Drawable本质也不是一张图,而是类似于View的图片载荷窗体。
二者其实是没有所谓的互转关系的,因为它们本质就是不同的二个东西,它们其实是生产关系,Bitmap可以生产Drawable,Drawable可以生产Bitmap。
二、Bitmap生产Drawable
ktx有现成的封装的方法:
val bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888)
bitmap.toDrawable(resources)
toDrawable的源码:
/** Create a [BitmapDrawable] from this [Bitmap]. */
public inline fun Bitmap.toDrawable(
resources: Resources
): BitmapDrawable = BitmapDrawable(resources, this)
BitmapDrawable这个类作为中间的生产工具
三、Drawable生产Bitmap
ktx有现成的封装的方法:
val drawable = ColorDrawable()
drawable.toBitmap()
toBitmap的源码:
public fun Drawable.toBitmap(
@Px width: Int = intrinsicWidth,
@Px height: Int = intrinsicHeight,
config: Config? = null
): Bitmap {
if (this is BitmapDrawable) { //如果已经是BitmapDrawable
if (config == null || bitmap.config == config) {
// Fast-path to return original. Bitmap.createScaledBitmap will do this check, but it
// involves allocation and two jumps into native code so we perform the check ourselves.
if (width == intrinsicWidth && height == intrinsicHeight) {
return bitmap //直接返回
}
return Bitmap.createScaledBitmap(bitmap, width, height, true)
}
}
val (oldLeft, oldTop, oldRight, oldBottom) = bounds
//如果不是就创建位图,将位图绘制在Drawable上
val bitmap = Bitmap.createBitmap(width, height, config ?: Config.ARGB_8888)
setBounds(0, 0, width, height)
draw(Canvas(bitmap))
setBounds(oldLeft, oldTop, oldRight, oldBottom)
return bitmap
}
4、自定义Drawable
一般情况下系统自带Drawable已经够用了,但是有时候我们需要在一个基础控件(自定义Drawable)上绘制不同的自定义View,那么去自定义一个Drawable就有必要。举个例子,比如我们需要在国际象棋的棋盘上绘制棋子,那么我们绘制一个国际象棋的棋盘给View用就很方便,并且可以减少View的嵌套层级优化性能。看如下代码:
要实现的棋盘效果
自定义Drawable
private const val GRID_NUMBER = 8 //横向和纵向格子的个数
class ChessDrawable : Drawable() {
private var tempX = 1 //行
private var tempY = 1 //列
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.BLACK
style = Paint.Style.FILL
}
override fun draw(canvas: Canvas) {
while (tempX <= GRID_NUMBER) {
tempY = 1
if (tempX % 2 != 0) { //奇数行
while (tempY <= GRID_NUMBER) {
if (tempY % 2 != 0) { //奇数列
paint.color = "#ECAB98".toColorInt()
} else { //偶数列
paint.color = "#FB7449".toColorInt()
}
drawChess(canvas)
tempY++
}
} else { //偶数行
while (tempY <= GRID_NUMBER) {
if (tempY % 2 != 0) { //奇数列
paint.color = "#FB7449".toColorInt()
} else { //偶数列
paint.color = "#ECAB98".toColorInt()
}
drawChess(canvas)
tempY++
}
}
tempX++
}
}
private fun drawChess(canvas: Canvas) {
var xLeft = bounds.left.toFloat()
var yTop = bounds.top.toFloat()
var xRight = bounds.right.toFloat()
var yBottom = bounds.bottom.toFloat()
var interval = (xRight - xLeft) / GRID_NUMBER
canvas.drawRect(
xLeft + (tempY - 1) * interval,
yTop + (tempX - 1) * interval,
xLeft + tempY * interval,
yTop + tempX * interval,
paint
)
}
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
}
override fun getAlpha(): Int {
return paint.alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
paint.colorFilter = colorFilter
}
override fun getColorFilter(): ColorFilter? {
return paint.colorFilter
}
//不透明度
override fun getOpacity(): Int {
return when (paint.alpha) {
0 -> PixelFormat.TRANSPARENT //透明
0xFF -> PixelFormat.OPAQUE //不透明
else -> PixelFormat.TRANSLUCENT //半透明
}
}
}
自定义View中使用
class ChessView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
private val drawable = ChessDrawable()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
//引用很简单
drawable.setBounds(0, 0, width, height)
drawable.draw(canvas)
}
}
效果展示
--个人学习笔记--