Android中如何在Canvas上绘制无抗锯齿的VectorDrawable?
在Canvas上绘制VectorDrawable的优化方案
我懂你现在为了在Canvas上画VectorDrawable,先转成Bitmap的流程确实有点繁琐,而且还会额外占用内存空间。先帮你把现有转Bitmap的方法补全并梳理清楚,再给你分享更直接的绘制方案~
先补全你当前的Bitmap转换方法
你的思路是对的,针对低版本系统做了兼容,完整实现可以这样写:
fun getBitmapFromVectorDrawable(context: Context, drawableId: Int, width: Int, height: Int): Bitmap { var drawable = ContextCompat.getDrawable(context, drawableId) ?: return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888) // 针对Android 5.0以下版本做兼容处理 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { drawable = DrawableCompat.wrap(drawable).mutate() } val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) return bitmap }
这个方法能把指定尺寸的VectorDrawable转成Bitmap,之后你就可以用canvas.drawBitmap()来绘制了,但缺点是每次绘制都要生成Bitmap,内存开销不小,尤其是需要频繁更新或者绘制多个VectorDrawable的时候。
更高效的方案:直接在Canvas上绘制VectorDrawable
其实完全不需要转Bitmap,直接把VectorDrawable放到Canvas上绘制就行,同样做好版本兼容:
fun drawVectorDrawableOnCanvas(canvas: Canvas, context: Context, drawableId: Int, left: Int, top: Int, right: Int, bottom: Int) { var drawable = ContextCompat.getDrawable(context, drawableId) ?: return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { drawable = DrawableCompat.wrap(drawable).mutate() } // 设置Drawable的绘制区域 drawable.setBounds(left, top, right, bottom) // 直接在目标Canvas上绘制 drawable.draw(canvas) }
使用的时候就简单多了,比如你在自定义View的onDraw方法里直接调用:
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) // 绘制一个左上角(50,50),右下角(200,200)的VectorDrawable drawVectorDrawableOnCanvas(canvas, context, R.drawable.your_vector, 50, 50, 200, 200) }
这种方式省去了Bitmap的中间转换,内存占用更低,绘制效率也更高,而且还能直接利用Drawable的一些特性(比如颜色 tint 之类的),不用再去处理Bitmap的颜色修改。
额外提示:动态修改VectorDrawable的属性
如果需要修改VectorDrawable的颜色(比如tint),直接在绘制前设置就行,比如:
DrawableCompat.setTint(drawable, ContextCompat.getColor(context, R.color.your_tint_color))
这样比修改Bitmap颜色要方便得多~
内容的提问来源于stack exchange,提问作者Boris Rozhkovsky
相关产品推荐
相关产品推荐

