我有一个视图,它进行一些基本的绘制。之后,我想要画一个带有孔洞的矩形,以便只有先前绘制区域可见。我希望在启用硬件加速的情况下为我的视图提供最佳性能。
目前我有两种方法可以实现,但只有在禁用硬件加速时才有效,另一种则太慢。
方法1:软件加速(慢)
这不支持视图开启硬件加速,因为在此模式下不支持“canvas.clipPath”(我知道可以强制使用SW渲染,但我想避免这种情况)。
方法2:硬件加速(非常缓慢)
这显然很慢——每次绘制调用都会创建一个新的与视图大小相同的
方法三:硬件加速(快速,但在某些设备上不起作用)。
与硬件加速兼容的方法相同,但不需要额外的画布。然而,这种方法存在一个主要问题——它在强制使用软件渲染时可以运行,但在至少HTC One X(Android 4.0.4——可能还有其他设备)启用硬件渲染后,它会使圆形完全变黑。这可能与22361相关。
方法4:硬件加速(可接受,在所有设备上都有效)。根据Jan的建议改进方法2,我避免了在每次调用onDraw时创建位图,而是在onSizeChanged中创建。
目前我有两种方法可以实现,但只有在禁用硬件加速时才有效,另一种则太慢。
方法1:软件加速(慢)
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:硬件加速(非常缓慢)
// 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
。方法三:硬件加速(快速,但在某些设备上不起作用)。
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);
这种方法的性能不如第三种,但比第二种好得多,略优于第一种。
问题
我该如何以与硬件加速兼容的方式实现相同的效果(并且在设备上始终有效)?增加软件渲染性能的方法也是可以接受的。
NB: 当移动圆圈时,我只是使一个区域失效--而不是整个画布--因此在那里没有性能提升的空间。
Bitmap b
和Canvas c
是可能的吗?这样做会有帮助吗? - John DvorakonSizeChanged
中的b
和c
进行更新而不是在onDraw
中,那么你最终会在同一画布上多次绘制而不清除(因此你会得到多个图层)。实际上,如果我可以在onDraw
中清除b
,那么它就可以工作,这很可能是可行的 - 我会尝试一下,谢谢! - Joseph EarlonSizeChanged
中创建了位图b
和画布c
,然后在进行任何绘制之前只需要调用b.eraseColor(Color.Transparent)
来擦除c
上的任何先前绘制。如果我在接下来的一天左右没有得到更有用的答案,我会将您的评论标记为正确答案。虽然它仍不如第三种方法平滑,但比第二种好多了。 - Joseph Earlc.drawColor
不是已经重置了画布吗?这样b.eraseColor
就变得多余了吧? - John Dvorakc.drawColor
绘制的颜色不是完全不透明的话,那么这种情况更有可能发生;) 方法4是基于您的答案提出的问题。 - Joseph Earl