我正在使用Google Maps Marker Clustering Utility对标记进行聚类。它在双击时非聚集。是否可以单击手动完成。
答案 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)
对于想要展开群集且保持缩放级别的用户,请尝试以下步骤。这似乎很复杂,但事实并非如此。
假设您有一个名为位置的模型来实现 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;
}
}
将以下算法添加到您的项目中,并将位置替换为您自己的型号名称。注意:此算法只是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);
}
}
}
设置算法和群集点击侦听器
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;
}
});
对DistanceBasedAlgorithm如何启用uncluster
的一点解释在 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;
}
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);
}
}
自从我编写代码以来已经有一段时间了。我可能会错过一些东西如果您无法使此解决方案有效,请给我留言。谢谢!