Google Maps API v2会在MapFragment上绘制圈子的一部分

我需要画一些这样的东西,这些东西会被涂上,透明度也很低

也需要点击(onTouch事件等)

在这里输入图像描述

我知道在API v1中,你必须使用Overlay,并使用canvas和一些math来扩展它。 Google Map API v2最简单的方法是什么?

PS:半径是可变的。

(供进一步参考)编辑1:

我实现了CanvasTileProvider子类,并覆盖了它的onDraw()方法:

@Override void onDraw(Canvas canvas, TileProjection projection) { // TODO Auto-generated method stub LatLng tempLocation = moveByDistance(mSegmentLocation, mSegmentRadius, mSegmentAngle); DoublePoint segmentLocationPoint = new DoublePoint(0, 0); DoublePoint tempLocationPoint = new DoublePoint(0, 0); projection.latLngToPoint(mSegmentLocation, segmentLocationPoint); projection.latLngToPoint(tempLocationPoint, tempLocationPoint); float radiusInPoints = FloatMath.sqrt((float) (Math.pow( (segmentLocationPoint.x - tempLocationPoint.x), 2) + Math.pow( (segmentLocationPoint.y - tempLocationPoint.y), 2))); RectF segmentArea = new RectF(); segmentArea.set((float)segmentLocationPoint.x - radiusInPoints, (float)segmentLocationPoint.y - radiusInPoints, (float)segmentLocationPoint.x + radiusInPoints, (float)segmentLocationPoint.y + radiusInPoints); canvas.drawArc(segmentArea, getAdjustedAngle(mSegmentAngle), getAdjustedAngle(mSegmentAngle + 60), true, getOuterCirclePaint()); } 

另外,我从MapActivity添加了这个:

 private void loadSegmentTiles() { TileProvider tileProvider; TileOverlay tileOverlay = mMap.addTileOverlay( new TileOverlayOptions().tileProvider(new SegmentTileProvider(new LatLng(45.00000,15.000000), 250, 30))); } 

现在我想知道为什么我的弧不在地图上?

为了画圆段,我会注册一个TileProvider,如果这些段主要是静态的。 (Tiles通常只加载一次然后被caching。)为了检查点击事件,你可以注册一个onMapClickListener并且循环你的段来检查点击的LatLng是否在你的一个段内。 (请参阅下面的更多细节。)

这里是一个TileProvider的例子,你可以inheritance和实现onDraw方法。
一个重要的注意事项:子类必须是线程安全的! onDraw方法将被多个线程同时调用。 因此,避免在onDraw中更改任何全局variables!

 /* imports should be obvious */ public abstract class CanvasTileProvider implements TileProvider { private static int TILE_SIZE = 256; private BitMapThreadLocal tlBitmap; @SuppressWarnings("unused") private static final String TAG = CanvasTileProvider.class.getSimpleName(); public CanvasTileProvider() { super(); tlBitmap = new BitMapThreadLocal(); } @Override // Warning: Must be threadsafe. To still avoid creation of lot of bitmaps, // I use a subclass of ThreadLocal !!! public Tile getTile(int x, int y, int zoom) { TileProjection projection = new TileProjection(TILE_SIZE, x, y, zoom); byte[] data; Bitmap image = getNewBitmap(); Canvas canvas = new Canvas(image); onDraw(canvas, projection); data = bitmapToByteArray(image); Tile tile = new Tile(TILE_SIZE, TILE_SIZE, data); return tile; } /** Must be implemented by a concrete TileProvider */ abstract void onDraw(Canvas canvas, TileProjection projection); /** * Get an empty bitmap, which may however be reused from a previous call in * the same thread. * * @return */ private Bitmap getNewBitmap() { Bitmap bitmap = tlBitmap.get(); // Clear the previous bitmap bitmap.eraseColor(Color.TRANSPARENT); return bitmap; } private static byte[] bitmapToByteArray(Bitmap bm) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG, 100, bos); byte[] data = bos.toByteArray(); return data; } class BitMapThreadLocal extends ThreadLocal<Bitmap> { @Override protected Bitmap initialValue() { Bitmap image = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Config.ARGB_8888); return image; } } } 

使用传入onDraw方法的投影,首先获取平铺的边界。 如果边界内没有任何分段,则返回。 否则,将您的设置绘制到canvas上。 projection.latLngToPoint方法可以帮助您将LatLng转换为canvas的像素。

 /** Converts between LatLng coordinates and the pixels inside a tile. */ public class TileProjection { private int x; private int y; private int zoom; private int TILE_SIZE; private DoublePoint pixelOrigin_; private double pixelsPerLonDegree_; private double pixelsPerLonRadian_; TileProjection(int tileSize, int x, int y, int zoom) { this.TILE_SIZE = tileSize; this.x = x; this.y = y; this.zoom = zoom; pixelOrigin_ = new DoublePoint(TILE_SIZE / 2, TILE_SIZE / 2); pixelsPerLonDegree_ = TILE_SIZE / 360d; pixelsPerLonRadian_ = TILE_SIZE / (2 * Math.PI); } /** Get the dimensions of the Tile in LatLng coordinates */ public LatLngBounds getTileBounds() { DoublePoint tileSW = new DoublePoint(x * TILE_SIZE, (y + 1) * TILE_SIZE); DoublePoint worldSW = pixelToWorldCoordinates(tileSW); LatLng SW = worldCoordToLatLng(worldSW); DoublePoint tileNE = new DoublePoint((x + 1) * TILE_SIZE, y * TILE_SIZE); DoublePoint worldNE = pixelToWorldCoordinates(tileNE); LatLng NE = worldCoordToLatLng(worldNE); return new LatLngBounds(SW, NE); } /** * Calculate the pixel coordinates inside a tile, relative to the left upper * corner (origin) of the tile. */ public void latLngToPoint(LatLng latLng, DoublePoint result) { latLngToWorldCoordinates(latLng, result); worldToPixelCoordinates(result, result); result.x -= x * TILE_SIZE; result.y -= y * TILE_SIZE; } private DoublePoint pixelToWorldCoordinates(DoublePoint pixelCoord) { int numTiles = 1 << zoom; DoublePoint worldCoordinate = new DoublePoint(pixelCoord.x / numTiles, pixelCoord.y / numTiles); return worldCoordinate; } /** * Transform the world coordinates into pixel-coordinates relative to the * whole tile-area. (ie the coordinate system that spans all tiles.) * * * Takes the resulting point as parameter, to avoid creation of new objects. */ private void worldToPixelCoordinates(DoublePoint worldCoord, DoublePoint result) { int numTiles = 1 << zoom; result.x = worldCoord.x * numTiles; result.y = worldCoord.y * numTiles; } private LatLng worldCoordToLatLng(DoublePoint worldCoordinate) { DoublePoint origin = pixelOrigin_; double lng = (worldCoordinate.x - origin.x) / pixelsPerLonDegree_; double latRadians = (worldCoordinate.y - origin.y) / -pixelsPerLonRadian_; double lat = Math.toDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2); return new LatLng(lat, lng); } /** * Get the coordinates in a system describing the whole globe in a * coordinate range from 0 to TILE_SIZE (type double). * * Takes the resulting point as parameter, to avoid creation of new objects. */ private void latLngToWorldCoordinates(LatLng latLng, DoublePoint result) { DoublePoint origin = pixelOrigin_; result.x = origin.x + latLng.longitude * pixelsPerLonDegree_; // Truncating to 0.9999 effectively limits latitude to 89.189. This is // about a third of a tile past the edge of the world tile. double siny = bound(Math.sin(Math.toRadians(latLng.latitude)), -0.9999, 0.9999); result.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -pixelsPerLonRadian_; }; /** Return value reduced to min and max if outside one of these bounds. */ private double bound(double value, double min, double max) { value = Math.max(value, min); value = Math.min(value, max); return value; } /** A Point in an x/y coordinate system with coordinates of type double */ public static class DoublePoint { double x; double y; public DoublePoint(double x, double y) { this.x = x; this.y = y; } } } 

最后,您需要检查一下LatLng-Coordinate的点击是否在您的细分内。 因此,我会用LatLng-Coordinates列表来近似这个段,在你的情况下,一个简单的三angular形就足够了。 对于LatLng坐标的每个列表,即对于每个段,您可以调用如下所示:

 private static boolean isPointInsidePolygon(List<LatLng> vertices, LatLng point) { /** * Test is based on a horizontal ray, starting from point to the right. * If the ray is crossed by an even number of polygon-sides, the point * is inside the polygon, otherwise it is outside. */ int i, j; boolean inside = false; int size = vertices.size(); for (i = 0, j = size - 1; i < size; j = i++) { LatLng vi = vertices.get(i); LatLng vj = vertices.get(j); if ((vi.latitude > point.latitude) != (vj.latitude > point.latitude)) { /* The polygonside crosses the horizontal level of the ray. */ if (point.longitude <= vi.longitude && point.longitude <= vj.longitude) { /* * Start and end of the side is right to the point. Side * crosses the ray. */ inside = !inside; } else if (point.longitude >= vi.longitude && point.longitude >= vj.longitude) { /* * Start and end of the side is left of the point. No * crossing of the ray. */ } else { double crossingLongitude = (vj.longitude - vi.longitude) * (point.latitude - vi.latitude) / (vj.latitude - vi.latitude) + vi.longitude; if (point.longitude < crossingLongitude) { inside = !inside; } } } } return inside; } 

正如你所看到的,我有一个非常类似的任务来解决:-)

创build一个视图,重写它的onDraw方法在其canvas上使用drawArc,并将其添加到你的MapFragment中。 您可以在drawArc中指定半径。 在View上设置onClickListener(或onTouch,任何可以用于普通视图的侦听器)。