draw circle with transparency in mapview

橙三吉。 提交于 2019-12-11 03:56:40

问题


I have a problem with mapview and Overlay.

I must to draw a circle on the map everytime that change GPS position. I used the method draw in my overlay class that extend overlay. The problem is that I must draw these circles with transparency, but when the circles overlap each other in the intersection point the color it's different because there is a sum of alpha.

How I can fix it?

This is my overlay class:

public class ImpactOverlay extends Overlay {

private static int CIRCLERADIUS = 0;
private GeoPoint geopoint;
private int myCircleRadius;
Point point = new Point();
Paint circle = new Paint(Paint.ANTI_ALIAS_FLAG);
private long systemTime= -1 ;



public ImpactOverlay(GeoPoint point, int myRadius) {

    geopoint = point;
    CIRCLERADIUS = myRadius; // assegna raggio del cerchio
}

@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {

     // Transfrom geoposition to Point on canvas
     Projection projection = mapView.getProjection();
     projection.toPixels(geopoint, point);

     // the circle to mark the spot
     circle.setColor(Color.parseColor("#88ff0000"));
     circle.setAlpha(122); // trasparenza

     myCircleRadius = metersToRadius(CIRCLERADIUS, mapView,
     (double) geopoint.getLatitudeE6() / 1000000);

     canvas.drawCircle(point.x, point.y, myCircleRadius, circle);       

}



public static int metersToRadius(float meters, MapView map, double latitude) {
    return (int) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math
            .cos(Math.toRadians(latitude))));
}

@Override
/* Implementa il doppio tap per eseguire zoom sulla mappa */
public boolean onTouchEvent(MotionEvent event, MapView mapView) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        if ((System.currentTimeMillis() - systemTime) < 250) {
            mapView.getController().zoomIn();
        }
        systemTime = System.currentTimeMillis();
        break;
    }

    return false;
}
}

回答1:


Well one possibility is to clip the area away which is intersecting the second circle like that, pseudo code:

canvas.clipPath(circle2.toPath())
canvas.draw(circle1)
canvas.removeClip()
canvas.draw(circle2)



回答2:


You need to take account of the intersection when you clip, something like this: .

@Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
                long when) {
    Paint paint = new Paint();
    paint.setColor(Color.parseColor("#88ff0000"));
    paint.setAlpha(16); // quite transparent
    Point point = new Point();
    Point point2 = new Point();
    float radius = 50.0f;

    Projection projection = mapView.getProjection();
    projection.toPixels(mGpt, point);   // 1st GeoPoint
    projection.toPixels(mGpt2, point2); // 2nd GeoPoint

    Path path1 = new Path();
    Path path2 = new Path();

    path1.addCircle(point.x, point.y, radius, Direction.CW);   // 1st circle
    path2.addCircle(point2.x, point2.y, radius, Direction.CW); // 2nd circle
    canvas.save(); // save canvas without the clip region
    canvas.clipPath(path2, Region.Op.DIFFERENCE); // clip the region
    // to the whole view less where circle2 will be when it's drawn
    canvas.drawPath(path1, paint); // draw 1st circle minus where it overlaps
    canvas.restore();              // clear the clip region
    canvas.drawPath(path2, paint); // draw 2nd circle (unclipped)
    return false;
}

should work




回答3:


You don't need to know how many shapes are there beforehand. If you use separate overlays you could just easily draw each and add the corresponding area to the clipping area.

Full code follows:

import java.util.List;

import android.graphics.*;
import android.graphics.Path.Direction;
import android.graphics.Region.Op;
import android.os.Bundle;
import android.view.MotionEvent;

import com.google.android.maps.*;

public class CircleTest extends MapActivity {
    private MapView m_map;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        m_map = (MapView) findViewById(R.id.mapview);
        m_map.displayZoomControls(true);
        m_map.setBuiltInZoomControls(true);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // m_map.getOverlays().add(new ); // some other overlays
        m_map.getOverlays().add(new ImpactGeneratorOverlay());
        // the impact areas are being inserted between these two, see ImpactGeneratorOverlay
        m_map.getOverlays().add(new ImpactClipRestoreOverlay());
    }

    /**
     * Restore clipping area to the saved one.
     */
    public static class ImpactClipRestoreOverlay extends Overlay {
        @Override
        public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
            super.draw(canvas, mapView, shadow);
            canvas.restore();
        }
    }

    /**
     * Handles events, on touch down it adds a new Impact area to the map,
     * just before the ClipRestore overlay (assume it's the last, if not store position, and insert before).
     */
    public static class ImpactGeneratorOverlay extends Overlay {
        @Override
        public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
            super.draw(canvas, mapView, shadow);
            canvas.save();
        }

        @Override
        public boolean onTouchEvent(final MotionEvent e, final MapView mapView) {
            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    GeoPoint point = mapView.getProjection().fromPixels((int) e.getX(), (int) e.getY());
                    List<Overlay> overlays = mapView.getOverlays();
                    overlays.add(overlays.size() - 1, new ImpactOverlay(point, 1000));
                    break;
            }
            return super.onTouchEvent(e, mapView);
        }
    }

    /**
     * Draw impact and remove the current shape path from the drawable area.
     */
    public static class ImpactOverlay extends Overlay {
        // shape parameters
        private final GeoPoint  circleCenter;
        private final int       circleRadius;

        // drawing cache
        private final Point     circleDrawCenter    = new Point();
        private final Paint     circlePaint         = new Paint();

        public ImpactOverlay(final GeoPoint circleCenter, final int circleRadius) {
            this.circleCenter = circleCenter;
            this.circleRadius = circleRadius;

            circlePaint.setAntiAlias(true);
            circlePaint.setColor(Color.argb(64, 255, 0, 0));
        }

        @Override
        public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
            // Transfrom geoposition to Point on canvas
            Projection projection = mapView.getProjection();
            projection.toPixels(circleCenter, circleDrawCenter);

            // the circle to mark the spot
            float circleDrawRadius = ImpactOverlay.metersToRadius(mapView, circleRadius, circleCenter.getLatitudeE6() / 1e6f);

            // create circle from path
            Path path = new Path();
            path.addCircle(circleDrawCenter.x, circleDrawCenter.y, circleDrawRadius, Direction.CW);

            // draw circle
            canvas.drawPath(path, circlePaint);

            // remove circle from further posibble drawing areas
            canvas.clipPath(path, Op.DIFFERENCE);
        }

        public static float metersToRadius(final MapView map, final float meters, final float latitude) {
            return (float) (map.getProjection().metersToEquatorPixels(meters) * (1 / Math.cos(Math.toRadians(latitude))));
        }
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
}

This contains a fix for clipping unwanted layers, say the first one, but this can be avoided if you just gather all the circles in one overlay and draw them in one draw method.

The key is to draw and set clipping (even if they exist in different overlays, not advised!):

canvas.save();
canvas.drawPath(path1, paint);
canvas.clipPath(path1, Op.DIFFERENCE);
canvas.drawPath(path2, paint); // do not draw over path1
canvas.clipPath(path2, Op.DIFFERENCE);
canvas.drawPath(path3, paint); // do not draw over path1 + path2
canvas.clipPath(path3, Op.DIFFERENCE);
// do not draw over path1 + path2 + path3
canvas.restore();
canvas.drawPath(path4, paint); // draw over anything



回答4:


        CircleOptions circle = new CircleOptions();
        circle.center(new LatLng(latitude, longitude))
        .radius(1500)//in meters
        .strokeColor(Color.BLUE)//border color
        .strokeWidth(3.0f)//border width
        .fillColor(0x200000ff);//inside circle
        googleMap.addCircle(circle);//GoogleMap googleMap(initialize accordingly)


来源:https://stackoverflow.com/questions/9065597/draw-circle-with-transparency-in-mapview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!