Wykrawanie otworu w nakładce prostokątnej z włączoną akceleracją sprzętową na widoku
Mam widok, który wykonuje podstawowe rysowanie. Następnie chcę narysować prostokąt z dziurkowanym otworem, aby widoczny był tylko obszar poprzedniego rysunku. I chciałbym to zrobić z akceleracją sprzętową włączoną dla mojego widoku dla najlepszej wydajności.
Obecnie mam dwie metody, które działają, ale działają tylko wtedy, gdy wyłączone jest akceleracja sprzętowa, a druga jest zbyt wolna.
Metoda 1: przyspieszenie SW (powolne)
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);
To nie działa z akceleracją sprzętową włączoną dla widoku, ponieważ ' canvas.clipPath ' nie jest obsługiwany w tym trybie (wiem, że mogę wymusić renderowanie SW, ale chciałbym tego uniknąć).
Metoda 2: przyspieszenie HW (V. powolne)
// 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);
Gdzie gumka jest tworzona jako
eraser = new Paint()
eraser.setColor(0xFFFFFFFF);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Jest to oczywiście wolne-przy każdym wywołaniu rysowania tworzony jest nowy Bitmap
rozmiar widoku.
Metoda 3: przyspieszanie sprzętowe (szybkie, nie działa na niektórych urządzeniach)
canvas.drawColor(backColor);
canvas.drawCircle(cx, cy, radius, eraser);
To samo jako metoda kompatybilna z akceleracją sprzętową, ale nie wymaga dodatkowego płótna. Jest z tym jednak poważny problem - działa z wymuszonym renderowaniem SW, ale na HTC One X (Android 4.0.4-i prawdopodobnie niektórych innych urządzeniach) przynajmniej z włączonym renderowaniem HW pozostawia koło całkowicie czarne. Jest to prawdopodobnie związane z 22361.
Metoda 4: przyspieszenie sprzętowe (dopuszczalne, działa na wszystkich urządzeniach)
Zgodnie z sugestią Jana dotyczącą ulepszenia metody 2, I unikanie tworzenia bitmapy w każdym wywołaniu onDraw
, zamiast tego w onSizeChanged
:
if (w != oldw || h != oldh) {
b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
c = new Canvas(b);
}
A potem po prostu użyłem ich w 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);
Wydajność nie jest tak dobra jak Metoda 3, ale znacznie lepsza niż 2 i nieco lepsza niż 1.
Pytanie
Jak mogę osiągnąć ten sam efekt, ale zrobić to w sposób zgodny z akceleracją sprzętową (i to działa konsekwentnie na urządzeniach)? Metoda, która zwiększa wydajność renderowania SW będzie również akceptowalne.
NB: przesuwając okrąg wokół, unieważniam tylko region , a nie całe płótno , więc nie ma miejsca na poprawę wydajności.
1 answers
Zamiast przydzielać nowe płótno do każdego malowania, powinieneś być w stanie przydzielić je raz, a następnie ponownie użyć płótna do każdego malowania.
Na init i na resize:
Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
On repaint:
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-23 13:26:21