PorterduffXfermode: Löscht einen Abschnitt einer Bitmap

Das Ziel ist einfach, eine Bitmap zu zeichnen und darüber Formen zu zeichnen, die den darunter liegenden Bereich der Bitmap LÖSCHEN.

Ich habe einfachen Proof-of-Concept-Code erstellt, um zu verstehen, wie genau ich vorgehen soll. In den verschiedenen Threads hier habe ich zahlreiche Hinweise zur Verwendung gefunden:

android.graphics.PorterDuff.Mode.CLEAR

Der folgende Code erstellt einfach einen Bildschirm mit blauem Hintergrund und fügt eine benutzerdefinierte Ansicht hinzu. In dieser Ansicht werden auf der Leinwand ein rosa Hintergrund, das Bitmap-Bild (mit einem leichten Rand, um den rosa Hintergrund anzuzeigen) und gelbe überlagernde Kreise für jeden PorterDuffXfermode gezeichnet.

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.RelativeLayout;

public class Test extends Activity {
    Drawing d = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        RelativeLayout.LayoutParams rlp = null;

        // Create the view for the xfermode test
        d = new Drawing(this);
        rlp = new RelativeLayout.LayoutParams(600, 900);
        rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
        d.setLayoutParams(rlp);

        RelativeLayout rl = new RelativeLayout(this);
        rl.setBackgroundColor(Color.rgb(0, 0, 255));
        rl.addView(d);

        // Show the layout with the test view
        setContentView(rl);
    }

    public class Drawing extends View {
        Paint[] pDraw = null;
        Bitmap bm = null;

        public Drawing(Context ct) {
            super(ct);

            // Generate bitmap used for background
            bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg");

            // Generate array of paints
            pDraw = new Paint[16];

            for (int i = 0; i<pDraw.length; i++) {
                pDraw[i] = new Paint();
                pDraw[i].setARGB(255, 255, 255, 0);
                pDraw[i].setStrokeWidth(20);
                pDraw[i].setStyle(Style.FILL);
            }

            // Set all transfer modes
            pDraw[0].setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            pDraw[1].setXfermode(new PorterDuffXfermode(Mode.DARKEN));
            pDraw[2].setXfermode(new PorterDuffXfermode(Mode.DST));
            pDraw[3].setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
            pDraw[4].setXfermode(new PorterDuffXfermode(Mode.DST_IN));
            pDraw[5].setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
            pDraw[6].setXfermode(new PorterDuffXfermode(Mode.DST_OVER));
            pDraw[7].setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
            pDraw[8].setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
            pDraw[9].setXfermode(new PorterDuffXfermode(Mode.SCREEN));
            pDraw[10].setXfermode(new PorterDuffXfermode(Mode.SRC));
            pDraw[11].setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
            pDraw[12].setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            pDraw[13].setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
            pDraw[14].setXfermode(new PorterDuffXfermode(Mode.SRC_OVER));
            pDraw[15].setXfermode(new PorterDuffXfermode(Mode.XOR));
        }

        @Override
        public void onDraw(Canvas canv) {
            // Background colour for canvas
            canv.drawColor(Color.argb(255, 255, 0, 255));

            // Draw the bitmap leaving small outside border to see background
            canv.drawBitmap(bm, null, new RectF(15, 15, getMeasuredWidth() - 15, getMeasuredHeight() - 15), null);

            float w, h;
            w = getMeasuredWidth();
            h = getMeasuredHeight();

            // Loop, draws 4 circles per row, in 4 rows on top of bitmap
            // Drawn in the order of pDraw (alphabetical)
            for(int i = 0; i<4; i++) {
                for(int ii = 0; ii<4; ii++) {
                    canv.drawCircle((w / 8) * (ii * 2 + 1), (h / 8) * (i * 2 + 1), w / 8 * 0.8f, pDraw[i*4 + ii]);
                }
            }
        }
    }

}

Dies ist das Ergebnis des Tests:

Der CLEAR-Modus befindet sich oben links und wird schwarz angezeigt.

In einem anderen Beispiel, in dem ich versuchte, dies zu verwenden, hatte ich ein DialogFragment, bei dem der CLEAR-Modus das gesamte DialogFragment löschte, damit die Aktivität darunter gesehen werden konnte. Daher habe ich in diesem Test viele verschiedene Hintergrundfarben verwendet.

Könnte dies möglicherweise dazu führen, dass die Pixel der gesamten Aktivität gelöscht werden, wie es in diesem anderen Beispiel der Fall war? Ich hätte gedacht, dass nur die Pixel der Arbeitsfläche, die sich auf die Ansicht beziehen, gelöscht werden könnten, aber in meinem anderen Beispiel wurden alle Pixel der benutzerdefinierten Ansicht, der zugrunde liegenden Bildansicht und des DialogFragment-Hintergrunds gelöscht.

Könnte mir bitte jemand helfen zu verstehen, was genau los ist und warum ich so schrecklich falsch liege?

Vielen Dank.

BEARBEITEN: Ich habe ein Beispiel reproduziert, das meinen Verdacht bestätigt. Wenn Sie genau diese benutzerdefinierte Ansicht hinzufügen, jedoch in einem DialogFragment, wird die zugrunde liegende Aktivität sichtbar.

Dies scheint mir ein ziemlich klarer Indikator dafür zu sein, dassMode.CLEAR löscht irgendwie auch die Leinwand der darunter liegenden Ansichten? Ich vermute, das Schwarz im ersten Beispiel ist das der Ansicht der obersten Ebene?

Ich denke, ich mache irgendwo etwas sehr Falsches: S

Antworten auf die Frage(3)

Ihre Antwort auf die Frage