绘制透明圆形并填充外部

8
我有一个地图视图,想在上面画一个圆来聚焦于特定区域。但是我希望这个圆是倒转的。也就是说,圆的内部不填充颜色,而是透明的,其他区域则填充颜色。看这张图片(http://i.imgur.com/zxIMZ.png),上半部分展示了普通圆形的效果,下半部分展示了“倒转”的圆形效果。
我已经尝试搜索,但是很难找到我想要的内容。有人知道我应该如何实现这样的效果吗?

你想要遮盖地图的“其余部分”,只留下一个圆形钥匙孔视图吗? - tony gil
3个回答

18

我的回答有点晚,但可能会帮助某些人实现这一点。以下是一个示例,说明如何制作半透明视图,其中透明圆形匹配最小尺寸的大小,在中心留有小间距。它可以放置在任何视图上方。

/*
 * 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
    }
}

以下是我的情况:

透明圆形叠加视图。


4
这对我很有帮助,但我遇到了一个问题。使用上面的代码,圆形内部呈现为黑洞。这篇文章建议在我的构造函数代码中添加以下内容来解决:setLayerType(View.LAYER_TYPE_SOFTWARE, null); - sidecarcat

1

你可以创建一个新的BufferedImage,将其填充为灰色,然后擦除你想要的圆形。

然后,在你的视图上绘制该BufferedImage。

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

3
据我所知,Android中没有AWT库,并且我找不到任何类似的东西可以完成这个功能。 - user1104351
@user1104351:哦,那很遗憾。BufferedImage是一个非常有用和强大的类。这真的很遗憾。我不熟悉Android。但我尝试过帮忙... - Martijn Courteaux

1

按照绘制普通圆的方法进行操作,但是要使用补集位置和补集半径。例如:

{0-Lat, (Long-180)%180, 20037508.34-Radius}

这是所有答案中唯一正确和完美的答案。需要被接受!但它需要在(0 - 纬度,经度 - 180)范围内。 - kaiser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接