Android如何在群集标记点击v2上单击时取消群集

时间:2014-08-20 01:18:32

标签: android google-maps

我正在使用Google Maps Marker Clustering Utility对标记进行聚类。它在双击时非聚集。是否可以单击手动完成。

3 个答案:

答案 0 :(得分:41)

派对迟到了,但我找到了这个答案here

在你的onClusterClick函数中:

LatLngBounds.Builder builder = LatLngBounds.builder();
for (ClusterItem item : cluster.getItems()) {
    builder.include(item.getPosition());
}
final LatLngBounds bounds = builder.build();
getMap().animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));

答案 1 :(得分:34)

    mClusterManager
            .setOnClusterClickListener(new OnClusterClickListener<MyItem>() {
                @Override
                public boolean onClusterClick(final Cluster<MyItem> cluster) {
                    map.animateCamera(CameraUpdateFactory.newLatLngZoom(
                            cluster.getPosition(), (float) Math.floor(map
                                    .getCameraPosition().zoom + 1)), 300,
                            null);
                    return true;
                }
            });

你也可以点击标记来做到这一点,  但在此之前你需要做map.setOnMarkerClickListener(mClusterManager);

以便集群管理器获取点击事件和 你可以做到

mClusterManagersetOnClusterItemClickListener(new OnClusterItemClickListener<MyItem>() {

}

答案 2 :(得分:1)

对于想要展开群集且保持缩放级别的用户,请尝试以下步骤。这似乎很复杂,但事实并非如此。

的步骤

  1. 假设您有一个名为位置的模型来实现 ClusterItem ,请添加以下代码:

    private boolean shouldCluster = true;
    
    public boolean isShouldCluster() {
        return shouldCluster;
    }
    
    public void setShouldCluster(boolean shouldCluster) {
        this.shouldCluster = shouldCluster;
    }
    

    整个模型看起来与此相似:

    public class Location implements ClusterItem
    {
        private double latitude;
    
        private double longitude;
    
        private boolean shouldCluster = true;
    
        @Override
        public LatLng getPosition() {
            return new LatLng(latitude, longitude);
        }
    
        @Override
        public String getTitle() {
            return null;
        }
    
        @Override
        public String getSnippet() {
            return null;
        }
    
        public boolean isShouldCluster() {
            return shouldCluster;
        }
    
        public void setShouldCluster(boolean shouldCluster) {
            this.shouldCluster = shouldCluster;
        }
    }
    
  2. 将以下算法添加到您的项目中,并将位置替换为您自己的型号名称。注意:此算法只是Google NonHierarchicalDistanceBasedAlgorithm的副本,并进行了一些修改。

    public class DistanceBasedAlgorithm implements Algorithm<Location> {
        public static final int MAX_DISTANCE_AT_ZOOM = 100; // essentially 100 dp.
    
        /**
         * Any modifications should be synchronized on mQuadTree.
         */
        private final Collection<QuadItem> mItems = new ArrayList<QuadItem>();
    
        /**
         * Any modifications should be synchronized on mQuadTree.
         */
        private final PointQuadTree<QuadItem> mQuadTree = new PointQuadTree<QuadItem>(0, 1, 0, 1);
    
        private static final SphericalMercatorProjection PROJECTION = new SphericalMercatorProjection(1);
    
        @Override
        public void addItem(Location item) {
            if (item == null) return;
    
            final QuadItem quadItem = new QuadItem(item);
            synchronized (mQuadTree) {
                mItems.add(quadItem);
                mQuadTree.add(quadItem);
            }
        }
    
        @Override
        public void addItems(Collection<Location> items) {
            for (Location item : items) {
                addItem(item);
            }
        }
    
        @Override
        public void clearItems() {
            synchronized (mQuadTree) {
                mItems.clear();
                mQuadTree.clear();
            }
        }
    
        @Override
        public void removeItem(Location item) {
            // QuadItem delegates hashcode() and equals() to its item so,
            //   removing any QuadItem to that item will remove the item
            final QuadItem quadItem = new QuadItem(item);
            synchronized (mQuadTree) {
                mItems.remove(quadItem);
                mQuadTree.remove(quadItem);
            }
        }
    
        @Override
        public Set<? extends Cluster<Location>> getClusters(double zoom) {
            final int discreteZoom = (int) zoom;
    
            final double zoomSpecificSpan = MAX_DISTANCE_AT_ZOOM / Math.pow(2, discreteZoom) / 256;
    
            final Set<QuadItem> visitedCandidates = new HashSet<QuadItem>();
            final Set<Cluster<Location>> results = new HashSet<Cluster<Location>>();
            final Map<QuadItem, Double> distanceToCluster = new HashMap<QuadItem, Double>();
            final Map<QuadItem, StaticCluster<Location>> itemToCluster = new HashMap<QuadItem, StaticCluster<Location>>();
    
            synchronized (mQuadTree) {
                for (QuadItem candidate : mItems) {
                    if (visitedCandidates.contains(candidate)) {
                        // Candidate is already part of another cluster.
                        continue;
                    }
    
                    Collection<QuadItem> clusterItems;
    
                    if (candidate.mClusterItem.isShouldCluster()) {
                        Bounds searchBounds = createBoundsFromSpan(candidate.getPoint(), zoomSpecificSpan);
                        clusterItems = mQuadTree.search(searchBounds);
                    }
                    else {
                        List<QuadItem> temp = new ArrayList<>();
                        temp.add(candidate);
                        clusterItems = temp;
                    }
    
                    if (clusterItems.size() == 1) {
                        // Only the current marker is in range. Just add the single item to the results.
                        results.add(candidate);
                        visitedCandidates.add(candidate);
                        distanceToCluster.put(candidate, 0d);
                        continue;
                    }
                    StaticCluster<Location> cluster = new StaticCluster<Location>(candidate.mClusterItem.getPosition());
                    results.add(cluster);
    
                    for (QuadItem clusterItem : clusterItems) {
                        Double existingDistance = distanceToCluster.get(clusterItem);
                        double distance = distanceSquared(clusterItem.getPoint(), candidate.getPoint());
                        if (existingDistance != null) {
                            // Item already belongs to another cluster. Check if it's closer to this cluster.
                            if (existingDistance < distance) {
                                continue;
                            }
                            // Move item to the closer cluster.
                            itemToCluster.get(clusterItem).remove(clusterItem.mClusterItem);
                        }
                        distanceToCluster.put(clusterItem, distance);
                        cluster.add(clusterItem.mClusterItem);
                        itemToCluster.put(clusterItem, cluster);
                    }
                    visitedCandidates.addAll(clusterItems);
                }
            }
            return results;
        }
    
        @Override
        public Collection<Location> getItems() {
            final List<Location> items = new ArrayList<Location>();
            synchronized (mQuadTree) {
                for (QuadItem quadItem : mItems) {
                    items.add(quadItem.mClusterItem);
                }
            }
            return items;
        }
    
        private double distanceSquared(Point a, Point b) {
            return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
        }
    
        private Bounds createBoundsFromSpan(Point p, double span) {
            // TODO: Use a span that takes into account the visual size of the marker, not just its
            // LatLng.
            double halfSpan = span / 2;
            return new Bounds(
                    p.x - halfSpan, p.x + halfSpan,
                    p.y - halfSpan, p.y + halfSpan);
        }
    
        private static class QuadItem implements PointQuadTree.Item, Cluster<Location> {
            private final Location mClusterItem;
            private final Point mPoint;
            private final LatLng mPosition;
            private Set<Location> singletonSet;
    
            private QuadItem(Location item) {
                mClusterItem = item;
                mPosition = item.getPosition();
                mPoint = PROJECTION.toPoint(mPosition);
                singletonSet = Collections.singleton(mClusterItem);
            }
    
            @Override
            public Point getPoint() {
                return mPoint;
            }
    
            @Override
            public LatLng getPosition() {
                return mPosition;
            }
    
            @Override
            public Set<Location> getItems() {
                return singletonSet;
            }
    
            @Override
            public int getSize() {
                return 1;
            }
    
            @Override
            public int hashCode() {
                return mClusterItem.hashCode();
            }
    
            @Override
            public boolean equals(Object other) {
                if (!(other instanceof QuadItem)) {
                    return false;
                }
    
                return ((QuadItem) other).mClusterItem.equals(mClusterItem);
            }
        }
    }
    
  3. 设置算法和群集点击侦听器

    map.setOnMarkerClickListener(mClusterManager);
    mClusterManager.setAlgorithm(new DistanceBasedAlgorithm());
    mClusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<Location>() {
                @Override
                public boolean onClusterClick(Cluster<Location> cluster) {
                    for (Location location : cluster.getItems()) {
                        location.setShouldCluster(false);
                    }
                    mClusterManager.addItem(null); // this line resets the cache
                    mClusterManager.cluster(); // re-cluster
    
                    return false;
                }
            });
    
  4. 完成!
  5. 解释

    对DistanceBasedAlgorithm如何启用uncluster

    的一点解释
    1. getClusters 功能中,下面的代码段会检查该项目是否应为群集

              if (candidate.mClusterItem.isShouldCluster()) {
                  Bounds searchBounds = createBoundsFromSpan(candidate.getPoint(), zoomSpecificSpan);
                  clusterItems = mQuadTree.search(searchBounds);
              }
              else {
                  List<QuadItem> temp = new ArrayList<>();
                  temp.add(candidate);
                  clusterItems = temp;
              }
      
    2. addItem 函数的更改允许算法接受空值,从而允许PreCachingAlgorithmDecorator清除缓存。

      @Override
      public void addItem(Location item) {
          if (item == null) return; // this line is the key to reset cache
      
          final QuadItem quadItem = new QuadItem(item);
          synchronized (mQuadTree) {
              mItems.add(quadItem);
              mQuadTree.add(quadItem);
          }
      }
      
    3. 自从我编写代码以来已经有一段时间了。我可能会错过一些东西如果您无法使此解决方案有效,请给我留言。谢谢!