Google Maps Android v2中的群集标记

时间:2013-03-19 09:02:39

标签: android google-maps-android-api-2 markerclusterer

我必须从Google Maps Android v2 API在GoogleMap上放置不同的标记。问题是多个标记设置为相同的位置(lat / lng),因此用户只能看到“最新”标记。

是否有可能(在最好的情况下:库)从同一区域聚类不同的标记(与缩放级别相关)?

我已经阅读了 MarkerClusterer ,但这是专为JavaScript API设计的。

8 个答案:

答案 0 :(得分:22)

Google提供了一个实用程序来执行此操作,作为其Google Maps Android API实用程序库的一部分:

https://developers.google.com/maps/documentation/android/utility/marker-clustering

源于:

https://github.com/googlemaps/android-maps-utils

答案 1 :(得分:20)

我还没有机会尝试这个,但看起来非常有希望:

http://code.google.com/p/android-maps-extensions/

来自this post

这是另一个带有一些很酷的集群动画的库:

https://github.com/twotoasters/clusterkraf

答案 2 :(得分:7)

我有点晚了,但是Clusterkraf是一个很棒的图书馆,请查看:

https://github.com/twotoasters/clusterkraf

答案 3 :(得分:6)

对于正在寻找实现自己的群集代码的其他人。请非常快速地检查我的聚类算法并且效果非常好。

我查看了各种库,发现它们如此复杂,无法理解一个单词,所以我决定制作自己的聚类算法。这是我在java中的代码。

    static int OFFSET = 268435456;
        static double RADIUS = 85445659.4471;
        static double pi = 3.1444;

    public static double lonToX(double lon) {
        return Math.round(OFFSET + RADIUS * lon * pi / 180);
    }

    public static double latToY(double lat) {
        return Math.round(OFFSET
                - RADIUS
                * Math.log((1 + Math.sin(lat * pi / 180))
                        / (1 - Math.sin(lat * pi / 180))) / 2);
    }

    public static int pixelDistance(double lat1, double lon1, double lat2,
            double lon2, int zoom) {
        double x1 = lonToX(lon1);
        double y1 = latToY(lat1);

        double x2 = lonToX(lon2);
        double y2 = latToY(lat2);

        return (int) (Math
                .sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))) >> (21 - zoom);
    }

    static ArrayList<Cluster> cluster(ArrayList<Marker> markers, int zoom) {

        ArrayList<Cluster> clusterList = new ArrayList<Cluster>();

        ArrayList<Marker> originalListCopy = new ArrayList<Marker>();

        for (Marker marker : markers) {
            originalListCopy.add(marker);
        }

        /* Loop until all markers have been compared. */
        for (int i = 0; i < originalListCopy.size();) {

            /* Compare against all markers which are left. */

            ArrayList<Marker> markerList = new ArrayList<Marker>();
            for (int j = i + 1; j < markers.size();) {
                int pixelDistance = pixelDistance(markers.get(i).getLatitude(),
                        markers.get(i).getLongitude(), markers.get(j)
                                .getLatitude(), markers.get(j).getLongitude(),
                        zoom);

                if (pixelDistance < 40) {


                    markerList.add(markers.get(j));

                    markers.remove(j);

                    originalListCopy.remove(j);
                    j = i + 1;
                } else {
                    j++;
                }

            }

            if (markerList.size() > 0) {
 markerList.add(markers.get(i));                
Cluster cluster = new Cluster(clusterList.size(), markerList,
                        markerList.size() + 1, originalListCopy.get(i)
                                .getLatitude(), originalListCopy.get(i)
                                .getLongitude());
                clusterList.add(cluster);
                originalListCopy.remove(i);
                markers.remove(i);
                i = 0;

            } else {
                i++;
            }

            /* If a marker has been added to cluster, add also the one */
            /* we were comparing to and remove the original from array. */

        }
        return clusterList;
    }

Just pass in your array list here containing latitude and longitude then to display clusters. Here goes the function.


    @Override
    public void onTaskCompleted(ArrayList<FlatDetails> flatDetailsList) {

        LatLngBounds.Builder builder = new LatLngBounds.Builder();

        originalListCopy = new ArrayList<FlatDetails>();
        ArrayList<Marker> markersList = new ArrayList<Marker>();
        for (FlatDetails detailList : flatDetailsList) {

            markersList.add(new Marker(detailList.getLatitude(), detailList
                    .getLongitude(), detailList.getApartmentTypeString()));

            originalListCopy.add(detailList);

            builder.include(new LatLng(detailList.getLatitude(), detailList
                    .getLongitude()));

        }

        LatLngBounds bounds = builder.build();
        int padding = 0; // offset from edges of the map in pixels
        CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);

        googleMap.moveCamera(cu);

        ArrayList<Cluster> clusterList = Utils.cluster(markersList,
                (int) googleMap.getCameraPosition().zoom);

        // Removes all markers, overlays, and polylines from the map.
        googleMap.clear();

        // Zoom in, animating the camera.
        googleMap.animateCamera(CameraUpdateFactory.zoomTo(previousZoomLevel),
                2000, null);

        CircleOptions circleOptions = new CircleOptions().center(point) //
                // setcenter
                .radius(3000) // set radius in meters
                .fillColor(Color.TRANSPARENT) // default
                .strokeColor(Color.BLUE).strokeWidth(5);

        googleMap.addCircle(circleOptions);

        for (Marker detail : markersList) {

            if (detail.getBhkTypeString().equalsIgnoreCase("1 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk1)));
            } else if (detail.getBhkTypeString().equalsIgnoreCase("2 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk_2)));

            }

            else if (detail.getBhkTypeString().equalsIgnoreCase("3 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk_3)));

            } else if (detail.getBhkTypeString().equalsIgnoreCase("2.5 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk2)));

            } else if (detail.getBhkTypeString().equalsIgnoreCase("4 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk_4)));

            } else if (detail.getBhkTypeString().equalsIgnoreCase("5 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk5)));

            } else if (detail.getBhkTypeString().equalsIgnoreCase("5+ BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk_5)));

            }

            else if (detail.getBhkTypeString().equalsIgnoreCase("2 BHK")) {
                googleMap.addMarker(new MarkerOptions()
                        .position(
                                new LatLng(detail.getLatitude(), detail
                                        .getLongitude()))
                        .snippet(String.valueOf(""))
                        .title("Flat" + flatDetailsList.indexOf(detail))
                        .icon(BitmapDescriptorFactory
                                .fromResource(R.drawable.bhk_2)));

            }
        }

        for (Cluster cluster : clusterList) {

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            options.inPurgeable = true;
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                    R.drawable.cluster_marker, options);

            Canvas canvas = new Canvas(bitmap);

            Paint paint = new Paint();
            paint.setColor(getResources().getColor(R.color.white));
            paint.setTextSize(30);

            canvas.drawText(String.valueOf(cluster.getMarkerList().size()), 10,
                    40, paint);

            googleMap.addMarker(new MarkerOptions()
                    .position(
                            new LatLng(cluster.getClusterLatitude(), cluster
                                    .getClusterLongitude()))
                    .snippet(String.valueOf(cluster.getMarkerList().size()))
                    .title("Cluster")
                    .icon(BitmapDescriptorFactory.fromBitmap(bitmap)));

        }

    }

答案 4 :(得分:5)

您需要按照以下步骤操作:

  1. 我们需要实施/ instal Google Maps Android API utility library
  2. Android studio / Gradle:

    dependencies {
        compile 'com.google.maps.android:android-maps-utils:0.3+'
    }
    
    1. 其次,您需要阅读Google的官方文档 - &gt; Google Maps Android Marker Clustering Utility
    2. 添加简单的标记聚类器

        

      按照以下步骤创建一个包含十个标记的简单群集。该   结果将看起来像这样,虽然标记的数量   显示/群集将根据缩放级别而改变:

      Add a simple marker clusterer

      以下是所需步骤的摘要:

      1. 实施ClusterItem以在地图上表示标记。群集项将标记的位置作为LatLng对象返回。
      2. 添加新的ClusterManager以根据缩放级别对群集项目(标记)进行分组。
      3. 将地图的OnCameraChangeListener()设置为ClusterManager,因为ClusterManager实现了监听器。
      4. 如果您想要添加特定功能以响应标记点击事件,请将地图OnMarkerClickListener()设置为ClusterManager,因为ClusterManager会实现侦听器。
      5. 将标记输入ClusterManager
      6. 更详细地查看步骤:要创建包含十个标记的简单集群,首先要创建一个实现MyItem的{​​{1}}类。

        ClusterItem

        在地图活动中,添加public class MyItem implements ClusterItem { private final LatLng mPosition; public MyItem(double lat, double lng) { mPosition = new LatLng(lat, lng); } @Override public LatLng getPosition() { return mPosition; } } 并将其提供给群集项。请注意类型参数ClusterManager,它声明ClusterManager的类型为<MyItem>

        MyItem

        <强>演示

        https://www.youtube.com/watch?v=5ZnVraO1mT4

        <强> Github上

        如果您需要更多信息/已完成的项目,请访问:https://github.com/dimitardanailov/googlemapsclustermarkers

        如果您有更多问题,请与我联系。

答案 5 :(得分:4)

谁遇到麻烦 Clusterkraf (我无法让它工作!)以及谁不能使用 android-maps-extension 导致它随附一个自定义构建的Play服务库,我想建议这个其他库,它很小,编写得很好并且开箱即用:

  

Clusterer https://github.com/mrmans0n/clusterer

经过整整一个上午尝试使用其他两个库后,这一个节省了我的一天!

答案 6 :(得分:2)

  

如果您只获得最新的标记,则需要对所有标记进行聚类

> private ClusterManager<MyItem> mClusterManager;
  添加商品后

mClusterManager.addItem("your item");
mClusterManager.cluster();

答案 7 :(得分:0)

对于那些在使用Google Maps Android API实用程序库时遇到问题的人,我们已经创建了自己的快速群集库:https://github.com/sharewire/google-maps-clustering。它可以在地图上轻松处理20000个标记。