Android如何在集群标记上单击一次即可取消集群映射v2
我正在使用谷歌地图标记聚类实用程序对标记进行聚类。它在双击时松开。是否可以一次单击就手动执行此操作。晚会有点晚了Android如何在集群标记上单击一次即可取消集群映射v2,android,google-maps,Android,Google Maps,我正在使用谷歌地图标记聚类实用程序对标记进行聚类。它在双击时松开。是否可以一次单击就手动执行此操作。晚会有点晚了 mClusterManager .setOnClusterClickListener(new OnClusterClickListener<MyItem>() { @Override public boolean onClusterClick(final Cluster<
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;
}
});
在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));
对于希望扩展群集并保持缩放级别的用户,请尝试以下步骤。这似乎很复杂,但事实并非如此 台阶
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;
}
}
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);
}
}
}
我已经有一段时间没有写代码了。我可能会错过什么。如果您在解决此问题时遇到困难,请给我留言。谢谢 非常感谢你。成功了!没有想过获取当前缩放并增加它。但是这会取消集群中的“所有”项目吗?我不认为当有这么多的集群项目时,将缩放比例增加1就可以了。这并不能回答问题,你可以用正确的方式增加缩放比例:
CameraUpdateFactory.zoomIn()
,CameraUpdateFactory.zoomTo()
,CameraUpdateFactory.zoomBy()
如何再次启用集群?单击群集后,您设置了shouldcluster(false),但如何在地图滚动或任何其他操作中启用它?@NickUnuchek,已经有一段时间了。我记不起细节了。我相信DistanceBasedAlgorithm.getClusters会重新创建所有项目,当应用操作时,默认情况下应该将Cluster设置为true。在我们的产品中,我们没有任何重新分类的问题。
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;
}
});
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;
}
@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);
}
}