自定义View:Bitmap和Drawable

837 阅读2分钟

一、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的嵌套层级优化性能。看如下代码:

要实现的棋盘效果

image.png

自定义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)
    }
}

效果展示

image.png

--个人学习笔记--