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, i
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:
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}
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();