Android Bitmap 和Drawable

314 阅读1分钟

前言

Android 中图片的显示基本都是基于Bitmap 和 Drawable 去绘制的.本文主要介绍其区别和作用

Bitmap是什么?

Bitmap是用于存储位图像素信息的数据.

Drawable 是什么?

  • 一种可以在Canvas上进行绘制的抽象的概念

  • 颜色、图片等都可以是一个Drawable

  • Drawable可以通过XML定义,或者通过代码创建

  • Android中Drawable是一个抽象类,每个具体的Drawable都是其子类

Bitmap 和Drawable的转换

  • Bitmap 转为Drawable对象

    Bitmap转为Drawable对象是很简单的,将Bitmap作为参数传入,创见一个BitmapDrawable对象即可,BitmapDrawable集成了Drawable对象

public static Drawable bitMapToDrawable(Resources resource, Bitmap bitmap) {
    return new BitmapDrawable(resource,bitmap);
}

以上是java代码,如果是kotlin,kotlin库中已经扩展了对应转换方法

bitmap.toDrawable(this.context.getResouces())
  • Drawable 转 Bitmap

Drawable 转Bitmap 对象的代码稍显复杂.

java 版本

public static Bitmap drawableToBitmap(Drawable drawable) {
    Bitmap bitmap = null;
    if ( drawable instanceof BitmapDrawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
        if(bitmapDrawable.getBitmap() != null) return bitmapDrawable.getBitmap();
    }
    if( drawable.getIntrinsicWidth() <= 0 ||  drawable.getIntrinsicHeight() <= 0) {
        // drawable 中高度 宽度存在问题时,返回一个像素大小的图
        bitmap = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888);
    } else {
        bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);
    }
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0,0,canvas.getWidth(),canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}

kotlin 版本

drawable.toBitmap(20,20,Bitmap.Config.ARGB_8888)//前两个参数用于设置宽高

Drawable 如何自定义

在Android SDK已经有了绝大多数的Drawable实现类,比如 ColorDrawable等,但是有时侯还是需要自定义的,比如画一个图表.自定义Drawable 的一个重要作用是可以作为自定义View的一个绘制模块,相当对View更加灵活.当多个View都要绘制某个图时,可以搬到一个Drawable中.下面看看如何自定义一个Drawable.

class DrawableTestView(context:Context, attributeSet: AttributeSet):View(context,attributeSet) {
   val pieDrawable = PieDrawable(values = arrayOf(100f,200f,300f), colors = arrayOf(Color.RED,Color.YELLOW,Color.GREEN))

   override fun onDraw(canvas: Canvas) {
      super.onDraw(canvas)
      // 绘制Drawable之前必须设置 bounds
      pieDrawable.setBounds(0,0, min(width,height), min(width,height))
      pieDrawable.draw(canvas)
   }
}

/**
 * @param values - 所有值数组
 * @param colors - 值对应的颜色数组
 */
class PieDrawable(val values : Array<Float>,val colors:Array<Int>) : Drawable(){
   private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
   override fun draw(canvas: Canvas) {
      if (values.size != colors.size) {
         return
      }
      val sum:Float = values.sum()
      var startAngle = 0f
      paint.style = Paint.Style.FILL_AND_STROKE
      for(i in 0 until values.size) {
         val sweepAngle = (values[i]/sum) * 360
         paint.color = colors[i]
         canvas.drawArc(bounds.toRectF(),startAngle,sweepAngle,true,paint)
         startAngle += sweepAngle
      }

   }

   /**
    * @param alpha - 范围[0-25],0表示完全透明,255完全不透明
    * 用于设置图片的透明度,简单的一个做法时直接将该值赋值为 paint.alpha.
    */
   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 getOpacity(): Int {
      return when(paint.alpha) {
         // 透明模式
         0 -> PixelFormat.TRANSLUCENT
         // 不透明模式
         0xff -> PixelFormat.OPAQUE
         // 半透明模式
         else -> PixelFormat.TRANSLUCENT
      }
   }

}