在Android MapView中绘制独立于缩放级别的形状

我需要绘制形状,就像使用Android的MapView在Google地图上创build自定义地图一样

换句话说,如果我在地图上绘制一个形状,当我缩小时,它应该缩小,覆盖地图的相同区域,而不pipe缩放级别如何。

遵循Android参考的示例:

@Override public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) { super.draw(canvas, mapView, shadow); //---translate the GeoPoint to screen pixels--- Point screenPts = new Point(); mapView.getProjection().toPixels(p, screenPts); Paint boxPaint = new Paint(); boxPaint.setColor(android.graphics.Color.WHITE); boxPaint.setStyle(Paint.Style.FILL); boxPaint.setAlpha(140); canvas.drawCircle(screenPts.x, screenPts.y, 20, boxPaint); return true; } 

这会在地图上显示一个白色圆圈,但是如果缩小,则圆圈的大小相同。 也许使用canvas不正确的做法?

我需要像Google地图突出显示街区或城市的内容:

Google Map显示纽约下东区的搜索结果

有任何想法吗? 提前致谢!

Solutions Collecting From Web of "在Android MapView中绘制独立于缩放级别的形状"

我自己也有同样的问题,下面是演示地点的完整解决scheme:

 import java.util.*; import android.graphics.*; import android.graphics.Paint.Style; import android.graphics.Region.Op; import android.os.Bundle; import com.google.android.maps.*; public class ShapeOverlayTest 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(); Loc[][] areas = { { new Loc(51.51695436113811, -0.28686325139653757), new Loc(51.5268179962453, -0.28118722558738923), new Loc(51.526498459594215, -0.27779666308279755), new Loc(51.52521530775356, -0.26943974607777654), new Loc(51.52292555645698, -0.25813738590178786), new Loc(51.52054465991048, -0.2498381618983569), new Loc(51.51012230470141, -0.24509233633017083), new Loc(51.50884762913046, -0.24465130560570497), new Loc(51.50732063336974, -0.2441767643132881), new Loc(51.50431624597833, -0.24473900326760137), new Loc(51.49756328092904, -0.2714528238165076), new Loc(51.50092541797557, -0.28360267232347336), new Loc(51.50205958485736, -0.28490018935582045), new Loc(51.50488447379555, -0.28681164237730944) }, { new Loc(51.50368617913765, -0.25313579464343156), new Loc(51.51978611305675, -0.24842567405905958), new Loc(51.51039382684418, -0.24460628015366626), new Loc(51.508792552597576, -0.24397604687682156), new Loc(51.50713008309719, -0.24346350415674722), new Loc(51.502411013302684, -0.2508501075008919), new Loc(51.502377240039664, -0.25160073203846817), new Loc(51.50274364303565, -0.25204783703705536) }, { new Loc(51.49924084955314, -0.2858705706471945), new Loc(51.50212820259818, -0.2791479893522646), new Loc(51.49724510427319, -0.27427453152961206), new Loc(51.49429724502515, -0.2799184038304611), new Loc(51.494270969987404, -0.28180678948730314) } }; String[] areaNames = { "W3 Ealing", "W3 Hammersmith & Fulham", "W3 Hounslow" }; // for (Map.Entry<String, List<Loc>> area : m_areas.entrySet()) { // // to have much less points and make sure they are in order // // the demo data already has these properties // // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm#Pseudocode // area.setValue(Algo.convexHull(area.getValue())); // } Map<String, List<GeoPoint>> areaMap = new HashMap<String, List<GeoPoint>>(); for (int i = 0; i < areaNames.length; i++) { List<GeoPoint> points = new ArrayList<GeoPoint>(); for (int j = 0; j < areas[i].length; j++) { points.add(areas[i][j].toGeoPoint()); } areaMap.put(areaNames[i], points); } m_map.getOverlays().add(new AreasOverlay(areaMap)); // TODO determine location better, eg averaging area points GeoPoint center = new GeoPoint(51509704, -270710); m_map.getController().setCenter(center); m_map.getController().setZoom(15); } @Override protected boolean isRouteDisplayed() { return false; } static class Loc { private double m_lat; private double m_lon; public Loc(final double lat, final double lon) { m_lat = lat; m_lon = lon; } public GeoPoint toGeoPoint() { return new GeoPoint((int) (m_lat * 1e6), (int) (m_lon * 1e6)); } }; static class AreasOverlay extends Overlay { private final Map<String, List<GeoPoint>> m_areas; private final Paint m_paintFill; private final Paint m_paintStroke; private static final int ALPHA = 0x30ffffff; // 48 out of 255 transparent private static final int[] COLORS = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.GREEN, Color.BLUE }; static { for (int i = 0; i < AreasOverlay.COLORS.length; i++) { AreasOverlay.COLORS[i] &= AreasOverlay.ALPHA; } } public AreasOverlay(final Map<String, List<GeoPoint>> areaMap) { m_areas = areaMap; // prepare paints m_paintFill = new Paint(); m_paintFill.setStyle(Paint.Style.FILL); m_paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); m_paintStroke.setStyle(Style.STROKE); m_paintStroke.setAntiAlias(true); m_paintStroke.setStrokeWidth(3); } @Override public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) { super.draw(canvas, mapView, shadow); if (shadow) { return; } Projection projection = mapView.getProjection(); List<Path> areaPaths = getPaths(projection, m_areas); drawPaths(canvas, areaPaths); } private List<Path> getPaths(final Projection projection, final Map<String, List<GeoPoint>> areas) { List<Path> areaPaths = new ArrayList<Path>(areas.size()); for (Map.Entry<String, List<GeoPoint>> entry : areas.entrySet()) { List<GeoPoint> sourceList = entry.getValue(); Path path = new Path(); path.setFillType(Path.FillType.EVEN_ODD); Iterator<GeoPoint> it = sourceList.iterator(); Point point = nextDrawPoint(projection, it); path.moveTo(point.x, point.y); while (it.hasNext()) { point = nextDrawPoint(projection, it); path.lineTo(point.x, point.y); } path.close(); areaPaths.add(path); } return areaPaths; } /** * <ul> * <li>Draw with different colors. * <li>Draw strokes first for them to be always visible. * <li>Draw fills next with each removing from the drawable area. * </ul> */ private void drawPaths(final Canvas canvas, final List<Path> areaPaths) { int currentColorIndex; currentColorIndex = 0; for (Path path : areaPaths) { int currentColor = AreasOverlay.COLORS[currentColorIndex++]; currentColorIndex %= AreasOverlay.COLORS.length; m_paintStroke.setColor(currentColor & 0xff7f7f7f); // make it darker by clearing the high bit canvas.drawPath(path, m_paintStroke); } currentColorIndex = 0; for (Path path : areaPaths) { int currentColor = AreasOverlay.COLORS[currentColorIndex++]; currentColorIndex %= AreasOverlay.COLORS.length; m_paintFill.setColor(currentColor); canvas.drawPath(path, m_paintFill); canvas.clipPath(path, Op.DIFFERENCE); // don't allow to draw over each other } } private Point nextDrawPoint(final Projection projection, final Iterator<GeoPoint> it) { GeoPoint geo = it.next(); Point p = new Point(); projection.toPixels(geo, p); return p; } } } 

drawCircle的半径是以像素为单位的,所以圆的大小始终相同。 您必须根据缩放级别缩放半径。 下面的示例将绘制将扩展的JTS拓扑套件中的几何graphics。

 public class MapOverlay extends Overlay { private static final String TAG = MapOverlay.class.getName(); // Allocate once and reuse private final Paint mPaint = new Paint(); private final Path mPath = new Path(); // Region to highlight private Geometry mGeometry; /** * @param geometry Region to highlight on map */ public MapOverlay(Geometry geometry) { // Set region mGeometry = geometry; // Edit paint style mPaint.setDither(true); mPaint.setColor(Color.rgb(128, 136, 231)); mPaint.setAlpha(100); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(6); } /** * Draw the overlay over the map. * * @see com.google.android.maps.Overlay#draw(Canvas, MapView, boolean) */ @Override public void draw(Canvas canvas, MapView mapv, boolean shadow) { super.draw(canvas, mapv, shadow); if (mGeometry != null) { // TODO There could be more than one geometries Geometry g = mGeometry.getGeometryN(0); final Point p = new Point(); boolean first = true; mPath.reset(); for (Coordinate c : g.getCoordinates()) { // Convert lat/lon to pixels on screen // GeoPoint is immutable so allocation is unavoidable Projection projection = mapv.getProjection(); projection.toPixels(new GeoPoint((int) (cy * 1E6), (int) (cx * 1E6)), p); // Set path starting point to first coordinate // otherwise default start is (0,0) if (first) { mPath.moveTo(px, py); first = false; } // Add new point to path mPath.lineTo(px, py); } } // Draw the path with give paint canvas.drawPath(mPath, mPaint); } 

从这里改编: MapSelectionOverlay.java

这也许你在找什么: 可以“覆盖”的大小与Android上的谷歌地图放大一起吗?

 public class ImpactOverlay extends Overlay { private static int CIRCLERADIUS = 0; private GeoPoint geopoint; public ImpactOverlay(GeoPoint point, int myRadius) { geopoint = point; CIRCLERADIUS = myRadius; } @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { // Transfrom geoposition to Point on canvas Projection projection = mapView.getProjection(); Point point = new Point(); projection.toPixels(geopoint, point); // the circle to mark the spot Paint circle = new Paint(); circle.setColor(Color.BLACK); int 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)))); } } 

你需要的是你想在地图上绘制的每个形状的纬度/经度的列表。 在onDraw方法中,您需要迭代该列表(对于要绘制的每个形状),然后执行以下操作:

 //---translate the GeoPoint to screen pixels--- Point screenPts = new Point(); mapView.getProjection().toPixels(p, screenPts); 

然后在canvas上绘制形状。 IIRC无论缩放比例都能正常工作,因为mapView知道缩放级别,并为您提供该缩放级别的经纬度对的适当像素位置。