Um ein einfaches Spiel zu erstellen, habe ich eine Vorlage verwendet, die eine Leinwand mit Bitmaps wie folgt zeichnet:
private void doDraw(Canvas canvas) {
for (int i=0;i<8;i++)
for (int j=0;j<9;j++)
for (int k=0;k<7;k++) {
canvas.drawBitmap(mBits[allBits[i][j][k]], i*50 -k*7, j*50 -k*7, null); } }
(Die Zeichenfläche ist in "run ()" definiert / die SurfaceView befindet sich in einem GameThread.)
Meine erste Frage ist, wie ich die gesamte Leinwand für ein neues Layout löschen (oder neu zeichnen) kann .
Zweitens, wie kann ich nur einen Teil des Bildschirms aktualisieren?
// This is the routine that calls "doDraw":
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING)
updateGame();
doDraw(c); }
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c); } } } }
quelle
mSurfaceHolder.unlockCanvasAndPost(c)
und dannc = mSurfaceHolder.lockCanvas(null)
, dann enthält das neuec
nicht das gleiche wie das vorherigec
. Sie können nicht nur einen Teil einer SurfaceView aktualisieren, was das OP wohl gefragt hat.Canvas
hält alte Zeichnungen.Das Zeichnen transparenter Farben im PorterDuff-Löschmodus macht den Trick für das, was ich wollte.
quelle
Bitmap#eraseColor(Color.TRANSPARENT)
Option wie in der Antwort von HeMac unten.Color.TRANSPARENT
ist unnötig.PorterDuff.Mode.CLEAR
ist völlig ausreichend für eineARGB_8888
Bitmap, was bedeutet, dass Alpha und Farbe auf [0, 0] gesetzt werden. Eine andere Möglichkeit ist die VerwendungColor.TRANSPARENT
mitPorterDuff.Mode.SRC
.Fand dies in Google Groups und das hat bei mir funktioniert ..
Dadurch werden Zeichnungsrechtecke usw. entfernt, während die festgelegte Bitmap beibehalten wird.
quelle
Ich habe die Antwort von @mobistry ausprobiert:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
Aber es hat bei mir nicht funktioniert.
Die Lösung war für mich:
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
Vielleicht hat jemand das gleiche Problem.
quelle
Verwenden Sie die Rücksetzmethode der Path-Klasse
quelle
quelle
Bitte fügen Sie den folgenden Code in die Oberflächenansicht ein. Erweitern Sie den Klassenkonstruktor .............
Konstruktorcodierung
XML-Codierung
versuchen Sie oben Code ...
quelle
Hier ist der Code eines minimalen Beispiels, das zeigt, dass Sie immer jedes Pixel der Leinwand bei jedem Frame neu zeichnen müssen.
Diese Aktivität zeichnet jede Sekunde eine neue Bitmap in der SurfaceView, ohne zuvor den Bildschirm zu löschen. Wenn Sie es testen, werden Sie feststellen, dass die Bitmap nicht immer in denselben Puffer geschrieben wird und der Bildschirm zwischen den beiden Puffern wechselt.
Ich habe es auf meinem Handy (Nexus S, Android 2.3.3) und auf dem Emulator (Android 2.2) getestet.
quelle
SurfaceHolder.Callback
nicht nur so seinCallback
.Canvas
wenn wir den gesamten Bildschirm vollständig neu zeichnen möchten. Das macht meine Aussage über "frühere Zeichnungen" wahr. DasCanvas
hält vorherige Zeichnungen.Canvas
behält a frühere Zeichnungen bei. Dies ist jedoch völlig nutzlos. Das Problem besteht darin, dass Sie bei der VerwendunglockCanvas()
nicht wissen, was diese „vorherigen Zeichnungen“ sind, und nichts davon annehmen können. Wenn zwei Aktivitäten mit einer SurfaceView derselben Größe vorhanden sind, teilen sie möglicherweise dieselbe Leinwand. Vielleicht bekommen Sie einen Teil des nicht initialisierten RAM mit zufälligen Bytes. Vielleicht ist immer das Google-Logo im Canvas geschrieben. Du kannst es nicht wissen. Jede Anwendung, die nicht jedes Pixel nachherlockCanvas(null)
zeichnet, ist fehlerhaft.Für mich würde ein Anruf
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
oder ähnliches erst funktionieren, wenn ich den Bildschirm berühre. Also würde ich die obige Codezeile aufrufen, aber der Bildschirm würde erst gelöscht, nachdem ich dann den Bildschirm berührt habe. Was für mich also funktionierte, war aufzurufen,invalidate()
gefolgt voninit()
dem Aufruf zum Zeitpunkt der Erstellung, um die Ansicht zu initialisieren.quelle
quelle
Das Löschen auf Canvas in Java Android ist ähnlich wie das Löschen von HTML Canvas über Javascript mit globalCompositeOperation. Die Logik war ähnlich.
U wählt die Logik DST_OUT (Destination Out).
Hinweis: DST_OUT ist nützlicher, da es 50% löschen kann, wenn die Lackfarbe 50% Alpha hat. Um vollständig bis transparent zu löschen, muss das Alpha der Farbe 100% betragen. Es wird empfohlen, paint.setColor (Color.WHITE) aufzutragen. Stellen Sie sicher, dass das Canvas-Bildformat RGBA_8888 war.
Kehren Sie nach dem Löschen mit SRC_OVER (Source Over) zur normalen Zeichnung zurück.
Das Aktualisieren der Anzeige für kleine Bereiche muss buchstäblich auf Grafikhardware zugreifen und wird möglicherweise nicht unterstützt.
Am naheliegendsten für höchste Leistung ist die Verwendung einer Mehrbildebene.
quelle
Vergessen Sie nicht, invalidate () aufzurufen.
quelle
invalidate
nachdem Sie etwas gezeichnet haben?Versuchen Sie, die Ansicht bei onPause () einer Aktivität zu entfernen und onRestart () hinzuzufügen.
LayoutYouAddedYourView.addView (YourCustomView); LayoutYouAddedYourView.removeView (YourCustomView);
Sobald Sie Ihre Ansicht hinzufügen, wird die onDraw () -Methode aufgerufen.
YourCustomView ist eine Klasse, die die View-Klasse erweitert.
quelle
In meinem Fall zeichne ich meine Leinwand in ein lineares Layout. So reinigen und neu zeichnen:
und dann rufe ich die Klasse mit den neuen Werten auf:
Dies ist die Klasse Lienzo:
quelle
Mit dem folgenden Ansatz können Sie die gesamte Leinwand oder nur einen Teil davon löschen.
Bitte vergessen Sie nicht, die Hardwarebeschleunigung zu deaktivieren, da PorterDuff.Mode.CLEAR nicht mit der Hardwarebeschleunigung funktioniert und schließlich aufruft ,
setWillNotDraw(false)
da wir dieonDraw
Methode überschreiben .quelle
LAYER_TYPE_HARDWARE
zuLAYER_TYPE_SOFTWARE
Ihre erste Anforderung, wie Sie die gesamte Leinwand löschen oder neu zeichnen - Antwort - Verwenden Sie die Methode canvas.drawColor (color.Black), um den Bildschirm mit einer schwarzen Farbe oder einer von Ihnen angegebenen Farbe zu löschen.
Ihre zweite Anforderung, wie Sie einen Teil des Bildschirms aktualisieren - Antwort - zum Beispiel, wenn Sie alle anderen Dinge auf dem Bildschirm unverändert lassen möchten, aber in einem kleinen Bereich des Bildschirms, um eine Ganzzahl (z. B. Zähler) anzuzeigen, die alle fünf Sekunden zunimmt. Verwenden Sie dann die canvas.drawrect-Methode, um diesen kleinen Bereich zu zeichnen, indem Sie links oben rechts unten und malen angeben. Berechnen Sie dann Ihren Zählerwert (mit postdalayed für 5 Sekunden usw., ähnlich wie Handler.postDelayed (Runnable_Object, 5000);), konvertieren Sie ihn in eine Textzeichenfolge, berechnen Sie die x- und y-Koordinate in diesem kleinen Rechteck und verwenden Sie die Textansicht, um die Änderung anzuzeigen Zählerwert.
quelle
Ich musste einen separaten Zeichnungsdurchlauf verwenden, um die Leinwand zu löschen (sperren, zeichnen und entsperren):
quelle
Ruf einfach an
canvas.drawColor (Color.TRANSPARENT)
quelle
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
. Wenn ich mich nicht irre, kann die Farbe tatsächlich alles sein (muss nicht TRANSPARENT sein), daPorterDuff.Mode.CLEAR
nur der aktuelle Clip gelöscht wird (wie das Stanzen eines Lochs in die Leinwand).