腾讯地图SDK Android版开发 9 覆盖物示例3点聚合
前言
前文介绍了如何在地图上添加一个Overlay,本文重点介绍如何实现点聚合的功能。
- 点聚合:当地图上需要展示的marker过多,可能会导致界面上marker压盖、性能变差。使用点聚合功能,则可以解决该问题。
相关的类和接口
配置
腾讯地图SDK点聚合部分位于``com.tencent.tencentmap.mapsdk.vector.utils.clustering包中,因其依赖旧的
Android 支持库(
Support Library),还没有迁移到 AndroidX。为了确保与
AndroidX项目兼容,应启用
enableJetifier属性。启用
enableJetifier 后,
Gradle` 在构建过程中会自动处理这些转换,确保项目能够正常编译和运行。
启用 enableJetifier
的方法
gradle.properties
文件,添加以下属性:
android.useAndroidX=true
android.enableJetifier=true
android.useAndroidX=true
:表示项目使用 AndroidX 库。android.enableJetifier=true
:表示启用 Jetifier 工具,会自动将旧的支持库依赖项转换为 AndroidX 库依赖项。
点聚合
ClusterManager
点聚合管理类主要接口如图:
类 | 接口 | 说明 |
---|---|---|
ClusterManager(context, map) | 构造 | |
void | setAlgorithm(algorithm) | 设置聚合策略 |
void | setRenderer(renderer) | 设置聚合渲染器,默认使用的是DefaultClusterRenderer |
void | setOnClusterClickListener(onClusterClickListener) | 设置点聚合单击事件 |
void | setOnClusterItemClickListener(onClusterItemClickListener) | 设置点聚合单个点对象单击事件 |
void | addItems(items) | 添加多个单个点对象 |
void | clearItems() | 删除所有单个点对象 |
void | cluster() | 重新聚合时调用,如更改聚合配置或刷新地图状态 |
示例
界面布局
- 布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapMarkersActivity">
<com.tencent.tencentmap.mapsdk.maps.TextureMapView
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomView"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/mapview">
<RadioGroup
android:id="@+id/RadioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/background_dark"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingHorizontal="10dp">
<RadioButton
android:id="@+id/cluster"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setMarkerFlag"
android:text="点聚合"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/clear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setMarkerFlag"
android:text="清除"
android:textColor="@color/white"
android:textStyle="bold" />
</RadioGroup>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
MapMarks类
- 以下是
MapMarks
部分代码。
常量
public static final String CLUSTER = "Cluster"; // 点聚合
成员变量
// 覆盖物列表
List<Removable> overlays = new ArrayList<>();
// 点聚合管理类
ClusterManager<MyClusterItem> clusterManager;
// 选中的状态
List<String> selectedFlags = new ArrayList<>();
初始化
- 初始化点聚合管理类
// 实例化点聚合管理者并进行初始化
clusterManager = new ClusterManager<>(context, map);
// 默认聚合策略,调用时不必添加,如果需要其他聚合策略可以按以下代码修改
NonHierarchicalDistanceBasedAlgorithm<MyClusterItem> ndba =
new NonHierarchicalDistanceBasedAlgorithm<>(context);
// 设置点聚合生效距离,以dp为单位
ndba.setMaxDistanceAtZoom(35);
// 设置策略
clusterManager.setAlgorithm(ndba);
// 设置聚合渲染器,默认使用的是DefaultClusterRenderer,可以不调用下列代码
DefaultClusterRenderer<MyClusterItem> renderer = new DefaultClusterRenderer<>(context,
map, clusterManager);
// 设置最小聚合数量,默认为4,这里设置为2,即有2个以上不包括2个marker才会聚合
renderer.setMinClusterSize(2);
// 定义聚合的分段,当超过5个不足10个的时候,显示5+,其他分段同理
renderer.setBuckets(new int[]{5, 10, 20, 50});
clusterManager.setRenderer(renderer);
// 设置地图变换的监听接口
map.setOnCameraChangeListener(clusterManager);
selectedFlags.add(CLUSTER);
创建覆盖物
public void addMarkers() {
if (selectedFlags.isEmpty())
return;
for (String flag : selectedFlags) {
switch (flag) {
case CLUSTER:
addCluster();
break;
}
}
}
点聚合
private void addCluster() {
List<LatLng> points = new ArrayList<>();
points.add(new LatLng(39.963175, 116.400244));
points.add(new LatLng(39.942821, 116.369199));
points.add(new LatLng(39.939723, 116.425541));
points.add(new LatLng(39.906965, 116.401394));
points.add(new LatLng(39.956965, 116.331394));
points.add(new LatLng(39.886965, 116.441394));
points.add(new LatLng(39.996965, 116.411394));
List<MyClusterItem> items = new ArrayList<>();
for (int i = 0; i < points.size(); i++) {
// 创建覆盖物单个点对象
items.add(new MyClusterItem(points.get(i)));
}
clusterManager.addItems(items);
clusterManager.cluster();
// 点击事件
map.setOnMarkerClickListener(clusterManager);
clusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<MyClusterItem>() {
@Override
public boolean onClusterClick(Cluster<MyClusterItem> cluster) {
showToast("有" + cluster.getSize() + "个点");
return true;
}
});
clusterManager.setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MyClusterItem>() {
@Override
public boolean onClusterItemClick(MyClusterItem item) {
showToast("点击单个Item");
return true;
}
});
}
- 实现
ClusterItem
类
// ClusterItem接口的实现类
public static class MyClusterItem implements ClusterItem {
LatLng position;
public MyClusterItem(LatLng position) {
this.position = position;
}
@Override
public LatLng getPosition() {
return position;
}
}
移除覆盖物
public void removeOverlay() {
// 清除地图上所有的标注类(Marker、Polyline、Polygon,TileOverlay除外)
// map.clearAllOverlays();
// 从地图移除覆盖物
for (Removable overlay : overlays) {
if (!overlay.isRemoved())
overlay.remove();
}
overlays.clear();
// 删除点聚合
clusterManager.clearItems();
clusterManager.cluster();
}
设置属性
public void setFlags(String flag) {
selectedFlags.clear();
if (flag != null)
selectedFlags.add(flag);
removeOverlay();
addMarkers();
}
加载地图和移除地图
public void onMapLoaded() {
addMarkers();
}
public void onMapDestroy() {
removeOverlay();
}
MapMarkersActivity类
- 以下是
MapMarkersActivity
类部分代码
控件响应事件
public void setMarkerFlag(View view) {
boolean checked = ((RadioButton) view).isChecked();
if (!checked)
return;
int id = view.getId();
String flag;
if (id == R.id.cluster)
flag = MapMarkers.CLUSTER;
else if (id == R.id.clear)
flag = null;
else
return;
mapMarkers.setFlags(flag);
}
运行效果图
![]() | ![]() | ![]() |
---|