在视图上启用HW加速的情况下,在矩形覆盖层上打孔



我有一个视图,它可以进行一些基本的绘图。在这之后,我想画一个有孔的矩形,这样只有上一张图的一个区域可见。我希望在为我的视图启用硬件加速的情况下实现最佳性能。

目前,我有两种方法可以工作,但只有在禁用硬件加速时才能工作,另一种方法太慢。

方法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:HW加速(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);

与硬件加速兼容的方法相同,但不需要额外的画布。不过,这有一个主要问题——它可以强制进行软件渲染,但在HTC One X(Android 4.0.4,可能还有其他一些设备)上,至少在启用硬件渲染的情况下,它会让圆圈完全变黑。这可能与22361有关。

方法4:硬件加速(可接受,适用于所有设备)

根据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略好。

问题

如何在与硬件加速兼容的方式下实现相同的效果(在设备上始终有效)?提高软件渲染性能的方法也是可以接受的。

注意:当我移动圆圈时,我只是使一个区域无效,而不是整个画布无效,所以没有提高性能的空间。

您应该能够在每次重新绘制时分配一次新画布,然后重用画布,而不是在每次重新绘画时分配一个新画布。

在初始化和调整大小时:

Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

重新喷漆时:

b.eraseColor(Color.TRANSPARENT);
// needed if backColor is not opaque; thanks @JosephEarl
c.drawColor(backColor);
c.drawCircle(cx, cy, radius, eraser);
canvas.drawBitmap(b, 0, 0, null);

相关内容

最新更新