【问题标题】:Replacement for ItemizedOverlay in Google maps V2 for Android?替换 Android 版 Google 地图 V2 中的 ItemizedOverlay?
【发布时间】:2012-12-19 17:05:17
【问题描述】:

在 V1 的 Google Maps for Android 中,我使用 ItemizedOverlay 类实现了一种集群形式。每个集群都有一个中心点(纬度/经度)、半径(以英里为单位)和集群中的项目数。我使用 ItemizedOverlay.draw(Canvas, MapView, shadow) 使用 Canvas 对象方法(如 drawCircle() 和 drawText())绘制集群。每个簇由一个包含计数的实心圆(大小根据计数所需的空间)和一个显示半径的圆组成。

阅读 V2 上的文档并使用演示应用程序后,我发现没有与 ItemizedOverlay 等效的东西,也没有明显的替代方案。我怀疑这样做的唯一方法是自己维护一个集群列表,然后将 MapView 子类化并提供其 onDraw() 方法的实现。

我是否错过了 V2 API 中比子类化 MapView 更好的东西?

谢谢,

标记

【问题讨论】:

  • 我想到了另一种看似更好的选择:使用 Marker 类,但不是提供静态图像,而是通过创建所需大小的 Bitmap 对象并使用一个画布对象。标记
  • 上述替代方法可能需要省略集群半径,因为这会使整个事物(而不仅仅是包含计数的圆圈)受到命中测试,从而防止点击到达位于下方的事物半径圈但在计数圈之外。
  • 使用 Bitmap 对象会比使用 Drawable 获得性能提升吗?
  • Drawables 包装了其他对象类型,所以我怀疑它们能否表现得更好。但这在这种情况下无关紧要,因为我必须动态创建我给 Marker 类的内容 - 即,虽然它只是一个圆圈,但它必须容纳可能从一位数到六位数的计数的文本或者更多。我不想为此使用固定大小的资源,因为它必须调整大小以容纳尽可能多的数量。

标签: android maps


【解决方案1】:

经过一些研究,我没有找到比动态创建标记位图更好的选择。但我也在地图上用多边形创建圆圈。请注意,这并不是真正的高性能解决方案,但就我而言,这是一个不错的选择。 代码示例:

private static final int CIRCLE_POLYGON_VERTICES = 16;
private static final double EARTH_RADIUS = 6378.1d;


private List<LatLng> createCirclePolygon(LatLng center, double r) {
    List<LatLng> res = new ArrayList<LatLng>(CIRCLE_POLYGON_VERTICES);

    double r_latitude = MathUtils.rad2deg(r/EARTH_RADIUS);
    double r_longitude = r_latitude / Math.cos(MathUtils.deg2rad(center.latitude));

    for (int point = 0; point < CIRCLE_POLYGON_VERTICES + 1; point++) {
         double theta = Math.PI * ((double)point / (CIRCLE_POLYGON_VERTICES / 2));
         double circle_x = center.longitude + (r_longitude * Math.cos(theta));  
         double circle_y = center.latitude + (r_latitude * Math.sin(theta));     

         res.add(new LatLng(circle_y, circle_x));
     }
     return res;
}   

private Bitmap getClusteredLabel(String cnt, Context ctx) {
    Resources r = ctx.getResources();
    Bitmap res = BitmapFactory.decodeResource(r, R.drawable.map_cluster_bg);        
    res = res.copy(Bitmap.Config.ARGB_8888, true);
    Canvas c = new Canvas(res);

    Paint textPaint = new Paint();
    textPaint.setAntiAlias(true);
    textPaint.setTextAlign(Paint.Align.CENTER);
    textPaint.setTypeface(Typeface.DEFAULT_BOLD);
    textPaint.setColor(Color.WHITE);
    textPaint.setTextSize(21);      

    c.drawText(String.valueOf(cnt), res.getWidth()/2, res.getHeight()/2 + textPaint.getTextSize() / 3, textPaint);

    return res;
}   

public void createClusteredOverlay(MapPinData point, GoogleMap map, Context ctx) {
    if (point.getCount() > 1) {
        map.addMarker(new MarkerOptions().position(point.getLatLng()).anchor(0.5f, 0.5f).icon(BitmapDescriptorFactory.fromBitmap(getClusteredLabel(String.valueOf(point.getCount()), ctx))));

        map.addPolygon(new PolygonOptions()         
        .addAll(createCirclePolygon(point.getLatLng(), point.getRadius()))
        .fillColor(Color.argb(50, 0, 0, 10))     
        .strokeWidth(0)
        );
    } else {
        map.addMarker(new MarkerOptions().position(point.getLatLng()).title(point.getTitle()));
    }
}

我的 MathUtils 方法:

public static double deg2rad(double deg) {
    return (deg * Math.PI / 180.0);
}

public static double rad2deg(double rad) {
    return (rad * 180.0 / Math.PI);
}   

如果您的半径以英里为单位,则应将 EARTH_RADIUS 常量更改为英里,3963 AFAIK。

【讨论】:

  • 看起来这会产生某种形状的标记,其中包含在内部绘制的簇计数和表示半径的圆的周围近似值,所有这些标记的尺寸都相同?如果所有标记的大小相同并且每个半径始终可见,这是可行的,并且它确实确保只能点击标记。我希望找到一种方法来使用事件作为触发器来绘制半径,但理想的事件(长按)无法用于标记。
  • 您还可以使用内置方法进行 rad deg 转换。 1. Math.toDegrees(angrad) 2. Math.toRadians(angdeg)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多