Android Canvas: Draw Transparent Circle on Image

Android canvas: draw transparent circle on image

So finally I managed to do this.

Firstly I draw a semitransparent black rectangle on whole view.
After that using PorterDuff.Mode.CLEAR I cut a transparent circle to show cat's position.

I had problem with PorterDuff.Mode.CLEAR: firstly I was getting a black circle instead of a transparent one.

Thanks to Romain Guy's comments here: comment here I understood that my window is opaque and I should draw on another bitmap. And only after draw on View's canvas.

Here is my onDraw method:

private Canvas temp;
private Paint paint;
private Paint p = new Paint();
private Paint transparentPaint;

private void init(){
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
temp = new Canvas(bitmap);
paint = new Paint();
paint.setColor(0xcc000000);
transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}

protected void onDraw(Canvas canvas) {
temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), paint);
temp.drawCircle(catPosition.x + radius / 2, catPosition.y + radius / 2, radius, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, p);
}

Draw a transparent circle onto a filled android canvas

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);
}
}

Android Compose: draw transparent circle on image

You need to use clipPath in this case.

Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
val circlePath = Path().apply {
addOval(Rect(center, size.minDimension / 2))
}
clipPath(circlePath, clipOp = ClipOp.Difference) {
drawRect(SolidColor(Color.Black.copy(alpha = 0.8f)))
}
})

Android, canvas: How can I draw transparent circle without overprinting?

You can try to use Canvas.clipPath before filling area with black color to exclude area, which will be used later by circle.

How to create a 'transparent circle inside rectangle' shape in XML in Android?

I've been playing recently with something similar, and adapted it for you.
All the magic is happening in the onDraw :

public class FocusView extends View {
private Paint mTransparentPaint;
private Paint mSemiBlackPaint;
private Path mPath = new Path();

public FocusView(Context context) {
super(context);
initPaints();
}

public FocusView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaints();
}

public FocusView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaints();
}

private void initPaints() {
mTransparentPaint = new Paint();
mTransparentPaint.setColor(Color.TRANSPARENT);
mTransparentPaint.setStrokeWidth(10);

mSemiBlackPaint = new Paint();
mSemiBlackPaint.setColor(Color.TRANSPARENT);
mSemiBlackPaint.setStrokeWidth(10);
}

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

mPath.reset();

mPath.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, Path.Direction.CW);
mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);

canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, mTransparentPaint);

canvas.drawPath(mPath, mSemiBlackPaint);
canvas.clipPath(mPath);
canvas.drawColor(Color.parseColor("#A6000000"));
}
}

The trick here is to create a Path (the transparent circle) so that we can set the drawing method of the path to be "outside of the path" instead of "inside of the path". Finally we can simply clip the canvas to that path, and fill in the black color.

For you, you'll just need to change Color.BLACK to your color, as well as change the desired radius.

EDIT :
Oh and simply add it programmatically :
FocusView view = new FocusView(context)
your_layout.addView(view)

Or by XML :

<package_path_to_.FocusView
android:layout_width="match_parent"
android:layout_height="match_parent" />

EDIT2 : I just saw you wanted this for the onboarding of your app.
You might consider having a look at https://github.com/iammert/MaterialIntroView then

Android canvas: draw transparent circle on image

So finally I managed to do this.

Firstly I draw a semitransparent black rectangle on whole view.
After that using PorterDuff.Mode.CLEAR I cut a transparent circle to show cat's position.

I had problem with PorterDuff.Mode.CLEAR: firstly I was getting a black circle instead of a transparent one.

Thanks to Romain Guy's comments here: comment here I understood that my window is opaque and I should draw on another bitmap. And only after draw on View's canvas.

Here is my onDraw method:

private Canvas temp;
private Paint paint;
private Paint p = new Paint();
private Paint transparentPaint;

private void init(){
Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
temp = new Canvas(bitmap);
paint = new Paint();
paint.setColor(0xcc000000);
transparentPaint = new Paint();
transparentPaint.setColor(getResources().getColor(android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}

protected void onDraw(Canvas canvas) {
temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), paint);
temp.drawCircle(catPosition.x + radius / 2, catPosition.y + radius / 2, radius, transparentPaint);
canvas.drawBitmap(bitmap, 0, 0, p);
}


Related Topics



Leave a reply



Submit