Draw a transparent circle onto a filled android canvas
Asked Answered
H

1

5

enter image description here

I am trying to do something very simple (see above). I want all of the pixels of a canvas to be a solid color, except for the the pixels that fill a centered circle. I have read hundreds stack overflow post on this subject and have tried hundreds of things including setting the PorterDuff.Mode. Here is my current onDraw() of MyView extends View:

  protected void onDraw(Canvas canvas) {
    int w = canvas.getWidth();
    int h = canvas.getHeight();

    Paint framePaint = new Paint();
    framePaint.setStyle(Paint.Style.FILL);
    framePaint.setColor(Color.BLUE);
    canvas.drawRect(0, 0, w, h, framePaint);

    Paint transparentPaint = new Paint();
    transparentPaint.setColor(Color.TRANSPARENT);
    transparentPaint.setAntiAlias(true);
    canvas.drawCircle(w / 2, h / 2, (w + h) / 4, transparentPaint);
  }

Am I misunderstanding something, why cant I paint over an existing pixel with transparent paint. When I do this the pixel stays the same. When I use PorterDuff, the pixel turns black. Please help.

Hindsight answered 14/12, 2013 at 23:2 Comment(0)
O
11

Try this:

public class TransparentCircle extends View {

    Bitmap bm;
    Canvas cv;
    Paint eraser;

    public TransparentCircle(Context context) {
        super(context);
        Init();
    }

    public TransparentCircle(Context context, AttributeSet attrs) {
        super(context, attrs);
        Init();
    }

    public TransparentCircle(Context context, AttributeSet attrs,
                             int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Init();
    }

    private void Init(){

        eraser = new Paint();
        eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        eraser.setAntiAlias(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

        if (w != oldw || h != oldh) {
            bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            cv = new Canvas(bm);
        }
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int w = getWidth();
        int h = getHeight();
        int radius = w > h ? h / 2 : w / 2;

        bm.eraseColor(Color.TRANSPARENT);
        cv.drawColor(Color.BLUE);
        cv.drawCircle(w / 2, h / 2, radius, eraser);
        canvas.drawBitmap(bm, 0, 0, null);
        super.onDraw(canvas);
    }
}
Osmometer answered 15/12, 2013 at 17:11 Comment(4)
This worked! I removed the onSizeChanged() since these objects wont be changing size and did everything in onDraw(). Thanks!Hindsight
The reason of onSizeChanged() is to avoid create bitmap and canvas too many times. onDraw() is call more times than onSizeChange().Osmometer
I just noticed that this code produces a circle with rough edges. Is there any way to make it more smooth by using some anti-aliase setting?Hindsight
Just add this code eraser.setAntiAlias(true); after eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); in init method.Osmometer

© 2022 - 2024 — McMap. All rights reserved.