У меня есть представление, которое делает некоторый основной чертеж. После этого я хочу нарисовать прямоугольник с отверстием, пробитым так, чтобы видна только область предыдущего рисунка. И я хотел бы сделать это с аппаратным ускорением, включенным для моего представления, для лучшей производительности.
В настоящее время у меня есть два метода, которые работают, но работают только при отключении аппаратного ускорения, а в другом - слишком медленно.
Метод 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. Slow)
// 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: ускорение HW (быстро, не работает на некоторых устройствах)
canvas.drawColor(backColor);
canvas.drawCircle(cx, cy, radius, eraser);
То же, что и метод совместимости с ускорением HW, но не требуется дополнительный холст. Есть большая проблема с этим, хотя - он работает с SW-рендерингом, но на HTC One X (Android 4.0.4 - и, возможно, на некоторых других устройствах), по крайней мере, с рендерингом HW, он оставляет круг полностью черным. Вероятно, это связано с 22361.
Метод 4: ускорение HW (допустимо, работает на всех устройствах)
Согласно предложению Ян для улучшения метода 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.
Вопрос
Как я могу достичь такого же эффекта, но делать это в соответствии с HW-ускорением (AND, который работает последовательно на устройствах)? Также будет приемлемым метод, который увеличивает производительность рендеринга SW.
NB: При перемещении круга я просто аннулирую регион, а не весь холст, поэтому там нет места для улучшения производительности.