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