我有一个视图可以做一些基本的绘图。在此之后,我想绘制一个带有打孔的矩形,这样只有前一个绘图的一个区域是可见的。我想通过为我的视图启用硬件加速来实现这一点,以获得最佳性能。
目前我有两种可行的方法,但仅在禁用硬件加速且另一种太慢时才有效。
方法 1:SW 加速(慢速)
final int saveCount = canvas.save();
// Clip out a circle.
circle.reset();
circle.addCircle(cx, cy, radius, Path.Direction.CW);
circle.close();
canvas.clipPath(circle, Region.Op.DIFFERENCE);
// Draw the rectangle color.
canvas.drawColor(backColor);
canvas.restoreToCount(saveCount);
这不适用于为视图启用的硬件加速,因为此模式不支持“canvas.clipPath”(我知道我可以强制 SW 渲染,但我想避免这种情况)。
方法 2:硬件加速(V. 慢速)
// Create a new canvas.
final Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
final Canvas c = new Canvas(b);
// Draw the rectangle colour.
c.drawColor(backColor);
// Erase a circle.
c.drawCircle(cx, cy, radius, eraser);
// Draw the bitmap on our views canvas.
canvas.drawBitmap(b, 0, 0, null);
橡皮擦的创建位置
eraser = new Paint()
eraser.setColor(0xFFFFFFFF);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
这显然很慢——Bitmap
每次绘图调用都会创建一个新的视图大小。
方法3:硬件加速(速度快,在某些设备上不起作用)
canvas.drawColor(backColor);
canvas.drawCircle(cx, cy, radius, eraser);
与硬件加速兼容方法相同,但不需要额外的画布。但这有一个主要问题——它可以强制使用 SW 渲染,但在 HTC One X(Android 4.0.4——可能还有其他一些设备)上,至少启用了 HW 渲染,它会使圆圈完全变黑。这可能与22361有关。
方法四:硬件加速(可接受,适用于所有设备)
根据 Jan 提出的改进方法 2 的建议,我避免在每次调用时创建位图onDraw
,而是在onSizeChanged
:
if (w != oldw || h != oldh) {
b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
c = new Canvas(b);
}
然后只是在onDraw
:
if (overlayBitmap == null) {
b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
c = new Canvas(b);
}
b.eraseColor(Color.TRANSPARENT);
c.drawColor(backColor);
c.drawCircle(cx, cy, radius, eraser);
canvas.drawBitmap(b, 0, 0, null);
性能不如方法3,但比方法2好很多,略好于方法1。
问题
如何以与硬件加速兼容的方式实现相同的效果(并且在设备上始终如一地工作)?增加 SW 渲染性能的方法也是可以接受的。
注意:当移动圆圈时,我只是在使一个区域无效——而不是整个画布——所以那里没有性能改进的空间。