J'ai donc essayé le code d'ici: Création d'une ImageView avec un masque . J'utilise les images suivantes comme original et masque:
Cependant, le résultat que j'obtiens est le suivant:
Notez que l'arrière-plan de la fenêtre n'est pas noir, mais holo light (qui sur le Nexus de la galaxie ressemble à un gris très pâle, pas complètement blanc). La deuxième image est le résultat que j'obtiens lorsqu'un élément est sélectionné dans une vue de liste.
Si au lieu de cela, je crée un nouveau bitmap en utilisant le même algorithme, puis le passe à la vue d'image au lieu de remplacer onDraw (), il dessine correctement:
Canvas canvas = new Canvas();
Bitmap mainImage = //get original image
Bitmap maskImage = //get mask image
Bitmap result = Bitmap.createBitmap(mainImage.getWidth(), mainImage.getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(result);
Paint paint = new Paint();
Paint.setFilterBitmap(false);
canvas.drawBitmap(mainImage, 0, 0, Paint);
Paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(maskImage, 0, 0, Paint);
Paint.setXfermode(null);
imageView.setImageBitmap(result);
J'obtiens le résultat attendu:
Notez que le fondu est correctement appliqué. Cela est plus évident lorsqu'une sélection est effectuée.
Alors, que se passe-t-il avec la méthode onDraw d'ImageView pour créer ce fond noir au lieu de laisser transparaître l'arrière-plan de la fenêtre? Ce qui est intéressant, c'est que si l'image originale elle-même a une certaine transparence, cette transparence est respectée, par exemple:
Je ne peux pas le découvrir par moi-même. Je préférerais pouvoir le faire sur onDraw au lieu de pré-créer le bitmap car cela ne fonctionne que pour les bitmaps comme source et masque. Je veux pouvoir le faire avec d'autres dessinables comme des dégradés et des couleurs unies mais dans ces cas, la largeur et la hauteur ne sont pas définies.
J'ai trouvé la combinaison parfaite pour créer un masquage sans bordure noire après avoir recherché tous les messages de stackoverflow. Cela convient assez bien à mon objectif.
Actuellement, je crée une vue déplaçable en utilisant une image normale et une image de masquage (un png avec transparence), donc je devrai remplacer la fonction onDraw.
private Bitmap mImage = ...;
private Bitmap mMask = ...; // png mask with transparency
private int mPosX = 0;
private int mPosY = 0;
private final Paint maskPaint;
private final Paint imagePaint;
public CustomView (final Context context) {
maskPaint = new Paint();
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
imagePaint = new Paint();
imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
}
/* TODO
if you have more constructors, make sure you initialize maskPaint and imagePaint
Declaring these as final means that all your constructors have to initialize them.
Failure to do so = your code won't compile.
*/
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.drawBitmap(mMask, 0, 0, maskPaint);
canvas.drawBitmap(mImage, mPosX, mPosY, imagePaint);
canvas.restore();
}
Répondre à ma propre question. Le Xfermode fonctionnait comme prévu. La peinture rendait le résultat de la toile transparente (qui était la toile utilisée par l'activité de la fenêtre). Comme la toile elle-même était transparente, la fenêtre montrait ce qu'il y avait derrière: le fond noir.
Pour le faire correctement, en effet, un nouveau Bitmap doit être créé pour contenir le résultat du masque alpha. J'ai mis à jour le code pour prendre en compte les drawables de tous types.
Dans ce code, appliquez:
mask_over = BitmapFactory.decodeResource(
getResources(), mask_over1[0]);
icon = Bitmap.createScaledBitmap(icon, screenwidth, screenwidth, false);
mask_over = Bitmap.createScaledBitmap(mask_over, screenwidth, screenwidth, false);
back_img=createBitmap_ScriptIntrinsicBlur(Bitmap.createScaledBitmap(cropview.croppedImage, screenwidth, screenwidth, false),25.0f);
LinearLayout.LayoutParams layoutParams111 = new LinearLayout.LayoutParams(screenwidth, screenwidth);