Search code examples
androidmask

Android bitmap mask clear doesn't stick


I have a class called MaskView:

public class MaskView extends View
{
    private Context context;
    public Bitmap imageMask;
    public int maskXPos;
    public int maskYPos;

    private Paint maskPaint;

    public MaskView(Context context)
    {
        super(context);

        this.context = context;
        maskXPos = 0;
        maskYPos = 0;

        maskPaint = new Paint();
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

        // 90% alpha
        this.setBackgroundColor(Color.argb(230, 0, 0, 0));
    }

    @Override public void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        canvas.save();

        if(imageMask != null)
        {
            canvas.drawBitmap(imageMask, maskXPos, maskYPos, maskPaint);
        }

        canvas.restore();
    }
}

At the moment, I got an Activity that fades in my mask using alpha fade in animation.

During the animation, I see my black mask overlay with the circular cutout bitmap mask.

However, after the mask view finish animating in, the bitmap mask instead of staying transparent, it gets rendered, and so I see a black circular bitmap instead of circular hole in my Mask view.

Is there a way to get the bitmap mask to remain a bitmap mask, and not get rendered?


Solution

  • I found the solution...after a few hours :D

    Needed one line extra:

    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    

    I don't know what the implications are for setting the layer type to software, but on my Galaxy Nexus, the view is rendering fine with animation. Doesn't seem to be any bad performance here.

    Here's full code:

    public class MaskView extends View { private Context context; public Bitmap imageMask; public int maskXPos; public int maskYPos;

    private Paint maskPaint;
    
    public MaskView(Context context)
    {
        super(context);
    
        setClickable(true);
    
        this.context = context;
        maskXPos = 0;
        maskYPos = 0;
    
        maskPaint = new Paint();
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
    
        // ------------------------------------------------------
        // This line is needed for the mask to work
        // ------------------------------------------------------
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }
    
    @Override public void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
    
        canvas.drawColor(Color.argb(230, 0, 0, 0));
    
        if(imageMask != null)
        {
            canvas.drawBitmap(imageMask, maskXPos, maskYPos, maskPaint);
        }
    }
    

    }

    I discovered the solution after trying out this tutorial:

    https://medium.com/@rgomez/android-how-to-draw-an-overlay-with-a-transparent-hole-471af6cf3953#.7uxgln7n4

    Hope it helps others.