java - secciones - PorterduffXfermode: Borrar una sección de un mapa de bits
eliminar secciones en word 2016 (3)
El objetivo es simplemente dibujar un mapa de bits y, por encima de él, dibujar formas que BORREN el área subyacente del mapa de bits.
He creado un código de prueba de concepto simple para tratar de entender exactamente cómo debo hacerlo. En los diversos hilos aquí he encontrado numerosos consejos sobre el uso de:
android.graphics.PorterDuff.Mode.CLEAR
El siguiente código simplemente crea una pantalla con un fondo azul y agrega una vista personalizada. Esta vista dibuja en su lienzo un fondo rosa, la imagen de mapa de bits (con un borde pequeño para mostrar el fondo rosa) y círculos superpuestos de color amarillo que representan cada modo PorterDuffX.
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]);
}
}
}
}
}
Este es el resultado de la prueba:
El modo BORRAR es la parte superior izquierda, que se muestra en negro.
En otro ejemplo en el que intentaba usar esto, tenía un DialogFragment en el que el modo BORRAR borraba todo el DialogFragment para poder ver la actividad debajo. De ahí la razón por la que utilicé muchos colores de fondo diferentes en esta prueba.
¿Podría esto posiblemente estar borrando los píxeles de toda la actividad como ese otro ejemplo me llevó a creer? Pensé que solo se podrían borrar los píxeles del lienzo relacionados con la vista, pero en mi otro ejemplo, los píxeles de la vista personalizada, la vista de la imagen subyacente y el fondo de DialogFragment se borraron.
¿Podría alguien, por favor, ayudarme a entender qué es exactamente lo que está pasando y por qué me estoy yendo tan mal?
Gracias.
EDITAR: He reproducido un ejemplo que confirma mis sospechas. Al agregar esta vista personalizada exacta, pero en un DialogFragment, la actividad subyacente se vuelve visible.
Esto me parece un indicador bastante claro de que Mode.CLEAR
está borrando el lienzo de las vistas de abajo. Mi conjetura sería que el negro en el primer ejemplo es el de la vista de nivel superior?
Estoy pensando que estoy haciendo algo muy mal en alguna parte: S
Como señala Romain Guy aquí: las cosas de google que necesita escribir en el mapa de bits, no el lienzo con los círculos que está tratando de despejar, luego configurarlo en el lienzo principal de su Vista. Entonces, haz algo como:
// Generate bitmap used for background
bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg");
// Create the paint and set the bitmap
Canvas temp = new Canvas(bm.getHeight(), bm.getWidth, Config.ARGB_8888);
// in onDraw()
temp.drawCircle((w / 8) * (ii * 2 + 1), (h / 8) * (i * 2 + 1), w / 8 * 0.8f, pDraw[i*4 + ii]);
// After loop
canvas.drawBitmap(....);
Espero que esto ayude.
El problema es la aceleración de hardware. Desactívelo para la Vista particular que está pintando con BORRAR. Si está utilizando una vista personalizada, haga esto en los constructores:
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
También puede llamar a setLayerType en una referencia de vista.
No veo nada inesperado. En el caso particular de Mode.CLEAR
, tanto el color como el alfa del destino se borran, lo que permite que se muestre el fondo negro. Esta utility permite experimentar con varios modos, colores y valores alfa, y la fuente puede ofrecer alguna información. En la imagen de abajo (algo fechada), las áreas CLEAR
revelan el tenue gris a rayas provisto por el delegado de PanelUI
la plataforma.