Draw transparent circle filled outside
Asked Answered
D

3

8

I have a mapview that I want to draw a circle on to focus on a given area. But i want the circle to be inverted. That is, instead of the inside of the circle being filled, it is transparent and everything else is filled. See this picture for what i mean (http://i.imgur.com/zxIMZ.png). The top half shows what i could do with a normal circle. Bottom shows the "inverted" circle.

I've tried to search, but it's been kind of hard to find what i want. Does anyone know how i could go about doing something like this?

Denesedengue answered 18/12, 2011 at 10:6 Comment(1)
you want to mask out the "rest" of the map and leave only a circular keyhole view of the map?Soar
P
18

My answer is pretty late, but may help someone to achieve this. Here is an example how to make semitransparent view with transparent circle matching size of the smallest dimension, placed in center with small margin. It can be placed as overlay upon any view.

/*
 * Copyright (c) 2015 Singularex Inc.
 */

package your_package.ui.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import your_package.R;

/**
 * @author Victor Kosenko
 */
public class RadiusOverlayView extends LinearLayout {
    private Bitmap windowFrame;

    public RadiusOverlayView(Context context) {
        super(context);
    }

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

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

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public RadiusOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

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

        if (windowFrame == null) {
            createWindowFrame(); // Lazy creation of the window frame, this is needed as we don't know the width & height of the screen until draw time
        }

        canvas.drawBitmap(windowFrame, 0, 0, null);
    }

    protected void createWindowFrame() {
        windowFrame = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); // Create a new image we will draw over the map
        Canvas osCanvas = new Canvas(windowFrame); // Create a   canvas to draw onto the new image

        RectF outerRectangle = new RectF(0, 0, getWidth(), getHeight());

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // Anti alias allows for smooth corners
        paint.setColor(getResources().getColor(R.color.map_radius_outer)); // This is the color of your activity background
        paint.setAlpha(84);
        osCanvas.drawRect(outerRectangle, paint);

        paint.setColor(Color.TRANSPARENT); // An obvious color to help debugging
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); // A out B http://en.wikipedia.org/wiki/File:Alpha_compositing.svg
        float centerX = getWidth() / 2;
        float centerY = getHeight() / 2;
        float radius = Math.min(getWidth(), getHeight()) / 2 - getResources().getDimensionPixelSize(R.dimen.view_margin_small2);
        osCanvas.drawCircle(centerX, centerY, radius, paint);
    }

    @Override
    public boolean isInEditMode() {
        return true;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        windowFrame = null; // If the layout changes null our frame so it can be recreated with the new width and height
    }
}

And here how it looks in my case:

Transparent circle overlay view.

Protract answered 17/5, 2015 at 21:43 Comment(1)
This was very helpful to me but I ran into one issue. Using the above code, the inside of the circle rendered as a black hole. This post suggested to add the following to my constructor code to fix it: setLayerType(View.LAYER_TYPE_SOFTWARE, null);Mizzenmast
S
1

You can create a new BufferedImage, fill it grey then erase the circle where you want.

And then, draw that BufferedImage on top of your view.

BufferedImage img = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_RGBA);
Graphics2D g = img.createGraphics();

int ovalX = 50;
int ovalY = 70;
int ovalRadius = 20;

/* Draw the grey rectangle */
g.setColor(Color.GRAY);
g.fillRect(0, 0, sizeX, sizeY);

/* Enable Anti-Alias */
g.setRenderingHint(RenderingHints.HINT_ANTIALIAS, RenderingHints.VALUE_ANTIALIAS_ON);

/* Clear the circle away */
g.setComposite(AlphaComposite.CLEAR, 1.0f);
g.fillOval(ovalX - ovalRadius, ovalY - ovalRadius, 2 * ovalRadius, 2 * ovalRadius);

g.dispose();
Sama answered 18/12, 2011 at 10:17 Comment(2)
As far as i know the awt library isn't available in android and i can't find anything equivalent that could do this.Denesedengue
@user1104351: Oh, that is sad. BufferedImage is such a useful powerful class. That's very sad. I'm not familiar with Android. But I tried to help...Sama
F
1

Do as you would do to draw a normal circle but with complement location and complement radius. Like:

{0-Lat, (Long-180)%180, 20037508.34-Radius}
Fact answered 5/8, 2017 at 19:22 Comment(1)
This is the only correct and perfect answer of all. Need to be the accepted one! But it needs to be (0 - lat, lng - 180)Breebreech

© 2022 - 2024 — McMap. All rights reserved.