前文介绍了如何在地图上添加一个Overlay,本文重点介绍如何批量添加和删除,海量点和点聚合的功能。
百度地图BaiduMap
地图类除了提供添加一个覆盖物的接口外,还提供了批量添加和删除的接口:
addOverlay
接口可以向地图添加点、线、面、弧、圆和文本覆盖物。addOverlays
接口可以一次性向地图上添加大批量的点、线、面等覆盖物。clear
接口则一次性清除地图上的所有覆盖物(Overlay对象和infoWindow)。setOnMarkerClickListener
和removeMarkerClickListener
接口可以添加和移除Marker单击事件。类型 | 方法 | 说明 |
---|---|---|
Overlay | addOverlay (OverlayOptions options) |
向地图添加一个 Overlay |
List< Overlay > | addOverlays (List< OverlayOptions > options) |
向地图添加多个 Overlay |
void | clear () |
清空地图所有的 Overlay 覆盖物以及 InfoWindow |
void | setOnMarkerClickListener (BaiduMap.OnMarkerClickListener listener) |
设置地图 Marker 覆盖物点击事件监听者 自3.4.0版本起可设置多个监听对象, 停止监听时调用removeMarkerClickListener移除监听对象 |
void | removeMarkerClickListener (BaiduMap.OnMarkerClickListener listener) |
移除一个地图 Marker 覆盖物点击事件监听者 |
MultiPoint
海量点覆盖物,通过MultiPointOption
类来设置海量点图层的属性。
百度地图SDKBaiduMap
地图类与海量点相关的接口:
addOverlay
接口可以向地图添加海量点。
setOnMultiPointClickListener
接口设置海量点单击事件
类型 | 方法 | 说明 |
---|---|---|
void | setOnMultiPointClickListener (BaiduMap.OnMultiPointClickListener listener) |
设置地图 MultiPoint 覆盖物点击事件监听者 |
// 地图MultiPoint覆盖物点击事件监听接口
public interface OnMultiPointClickListener {
/**
* 地图 MultiPoint 覆盖物点击事件监听函数
* @param point 被点击的 MultiPoint
* @param item 被点击的 MultiPointItem
* @return
*/
boolean onMultiPointClick(MultiPoint point, MultiPointItem item);
}
类型 | 方法 | 说明 |
---|---|---|
BitmapDescriptor | getIcon () |
获取 MultiPoint 覆盖物图标 |
List< MultiPointItem > | getMultiPointItems () |
获取 MultiPoint 覆盖物数据集合 |
float | getAnchorX () |
获取 MultiPoint 覆盖物水平方向锚点比例 |
float | getAnchorY () |
获取 MultiPoint 覆盖物垂直方向锚点比例 |
int | getPointSizeHeight () |
获取 MultiPoint 覆盖物纹理点的高度 |
int | getPointSizeWidth () |
获取 MultiPoint 覆盖物纹理点的宽度 |
boolean | isVisible () |
获取MultiPoint 覆盖物可见性 |
类型 | 方法 | 说明 |
---|---|---|
MultiPointOption | setIcon (BitmapDescriptor icon) |
设置 MultiPoint 覆盖物的图标 (必填) |
MultiPointOption | setMultiPointItems (List< MultiPointItem > multiPointItems) |
添加海量点数据集合(必填) |
MultiPointOption | setPointSize (int pointSizeWidth, int pointSizeHeight) |
纹理渲染大小,默认为icon图片大小 |
MultiPointOption | setAnchor (float anchorX, float anchorY) |
设置 MultiPoint 覆盖物的锚点比例, 默认(0.5f, 0.5f)水平居中,垂直下对齐 |
MultiPointOption | setClickable (boolean isClickable) |
设置MultiPoint是否可点击 |
MultiPointOption | visible (boolean visible) |
设置MultiPoint 覆盖物可见性,默认 true 显示 |
类型 | 方法 | 说明 |
---|---|---|
MultiPointItem (LatLng point) |
MultiPoint覆盖物单个点构造函数 | |
LatLng | getPoint () |
获取MultiPoint覆盖物单个点经纬度 |
String | getTitle () |
获取MultiPoint覆盖物单个点标题 |
void | setTitle (String title) |
设置MultiPoint覆盖物单个点标题 |
百度地图SDK点聚合部分已开放源码,位于Demo
的clusterutil
包中,可以下载后自行修改使用。
相关代码文件清单:
com/baidu
└── mapapi
└── clusterutil
├── MarkerManager.java
├── clustering
│ ├── Cluster.java
│ ├── ClusterItem.java
│ ├── ClusterManager.java
│ ├── algo
│ │ ├── Algorithm.java
│ │ ├── NonHierarchicalDistanceBasedAlgorithm.java
│ │ ├── PreCachingAlgorithmDecorator.java
│ │ └── StaticCluster.java
│ └── view
│ ├── ClusterRenderer.java
│ └── DefaultClusterRenderer.java
├── projection
│ ├── Bounds.java
│ ├── Point.java
│ └── SphericalMercatorProjection.java
├── quadtree
│ └── PointQuadTree.java
└── ui
├── IconGenerator.java
├── RotationLayout.java
└── SquareTextView.java
相关资源文件清单:
└── res
├── layout
│ └── text_bubble.xml
├── raw
│ └── locations.json
└── values
└── styles.xml
<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.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clickable="true"
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/bmapView">
<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/bulk"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="true"
android:onClick="setMarkerFlag"
android:text="批量点"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/multiPoint"
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/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
部分代码。public static final String BULK = "Bulk"; // 批量点
public static final String MULTI_POINT = "MultiPoint"; // 海量点
public static final String CLUSTER = "Cluster"; // 点聚合
// 覆盖物列表
List<Overlay> overlays = new ArrayList<>();
// 海量点选中高亮
Marker selectedMarker;
// 点聚合管理类
ClusterManager<MyClusterItem> clusterManager;
// 选中的状态
List<String> selectedFlags = new ArrayList<>();
// 气泡图标
ArrayList<BitmapDescriptor> bitmaps = new ArrayList<>();
// 点图标
BitmapDescriptor dotBitmap;
// Marker点击事件
BaiduMap.OnMarkerClickListener bulkMarkerClickListener;
// 海量点点击事件
BaiduMap.OnMultiPointClickListener multiPointClickListener;
// 初始化点聚合管理类
clusterManager = new ClusterManager<>(context, map);
// 设置地图监听,当地图状态发生改变时,进行点聚合运算
map.setOnMapStatusChangeListener(clusterManager);
selectedFlags.add(BULK);
int[] drawableIds = BubbleIcons.Number;
for (int drawableId : drawableIds) {
BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(drawableId);
bitmaps.add(bitmap);
}
dotBitmap = BitmapDescriptorFactory.fromResource(CircleIcons.BLueDot[0]);
public void addMarkers() {
if (selectedFlags.isEmpty())
return;
for (String flag : selectedFlags) {
switch (flag) {
case BULK:
addBulk();
break;
case MULTI_POINT:
addMultiPoint();
break;
case CLUSTER:
addCluster();
break;
}
}
}
private void addBulk() {
// 构造大量坐标数据
List<LatLng> points = new ArrayList<>();
points.add(new LatLng(39.97923, 116.357428));
points.add(new LatLng(39.94923, 116.397428));
points.add(new LatLng(39.97923, 116.437428));
points.add(new LatLng(39.92353, 116.490705));
points.add(new LatLng(40.023537, 116.289429));
points.add(new LatLng(40.022211, 116.406137));
// 创建OverlayOptions的集合
List<OverlayOptions> optionsList = new ArrayList<>();
for (int i = 0; i < points.size(); ++i) {
// 创建OverlayOptions属性
OverlayOptions option = new MarkerOptions()
.position(points.get(i))
.icon(bitmaps.get(i));
// 将OverlayOptions添加到list
optionsList.add(option);
}
// 在地图上批量添加
List<Overlay> newOverlays = map.addOverlays(optionsList);
overlays.addAll(newOverlays);
// Marker单击事件
if (bulkMarkerClickListener == null) {
bulkMarkerClickListener = new BaiduMap.OnMarkerClickListener() {
// marker被点击时回调的方法
// 若响应点击事件,返回true,否则返回false
// 默认返回false
@Override
public boolean onMarkerClick(Marker marker) {
showToast("点击 marker");
return true;
}
};
}
map.setOnMarkerClickListener(bulkMarkerClickListener);
}
private void addMultiPoint() {
// 加载大量点(参考官网示例Demo)
List<LatLng> points = getLocations();
ArrayList<MultiPointItem> items = new ArrayList<>();
for (int i = 0; i < points.size(); i++) {
// 创建覆盖物单个点对象
MultiPointItem item = new MultiPointItem(points.get(i));
items.add(item);
}
// 设置海量点数据
MultiPointOption option = new MultiPointOption();
option.setMultiPointItems(items);
option.setIcon(dotBitmap);
// 添加海量点覆盖物
MultiPoint multiPoint = (MultiPoint) map.addOverlay(option);
overlays.add(multiPoint);
// 海量点单击事件
if (multiPointClickListener == null) {
multiPointClickListener = new BaiduMap.OnMultiPointClickListener() {
@Override
public boolean onMultiPointClick(MultiPoint point, MultiPointItem item) {
if (selectedMarker != null)
selectedMarker.remove();
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(item.getPoint());
markerOptions.icon(bitmaps.get(0));
selectedMarker = (Marker) map.addOverlay(markerOptions);
return true;
}
};
map.setOnMultiPointClickListener(multiPointClickListener);
}
}
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), bitmaps.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;
BitmapDescriptor bitmap;
public MyClusterItem(LatLng position, BitmapDescriptor bitmap) {
this.position = position;
this.bitmap = bitmap;
}
@Override
public LatLng getPosition() {
return position;
}
@Override
public BitmapDescriptor getBitmapDescriptor() {
return bitmap;
}
}
public void removeOverlay() {
// 批量删除添加的多个 Overlay
//map.removeOverLays(overlays);
// 清空地图所有的 Overlay 覆盖物以及 InfoWindow
// map.clear();
// 删除覆盖物
for (Overlay overlay : overlays) {
overlay.remove();
}
overlays.clear();
if (selectedMarker != null)
selectedMarker.remove();
selectedMarker = null;
// 删除点聚合
clusterManager.clearItems();
clusterManager.cluster();
// 避免批量与点聚合单击事件冲突
map.removeMarkerClickListener(bulkMarkerClickListener);
map.removeMarkerClickListener(clusterManager);
}
public void setFlags(String flag) {
selectedFlags.clear();
if (flag != null)
selectedFlags.add(flag);
removeOverlay();
addMarkers();
}
public void onMapLoaded() {
addMarkers();
}
public void onMapDestroy() {
removeOverlay();
for (BitmapDescriptor bitmap : bitmaps) {
bitmap.recycle();
}
bitmaps = null;
if (dotBitmap != null)
dotBitmap.recycle();
}
MapMarkersActivity
类部分代码public void setMarkerFlag(View view) {
boolean checked = ((RadioButton) view).isChecked();
if (!checked)
return;
int id = view.getId();
String flag;
if (id == R.id.bulk)
flag = MapMarkers.BULK;
else if (id == R.id.multiPoint)
flag = MapMarkers.MULTI_POINT;
else if (id == R.id.cluster)
flag = MapMarkers.CLUSTER;
else if (id == R.id.clear)
flag = null;
else
return;
mapMarkers.setFlags(flag);
}
批量点 | 海量点 | 点聚合 |
---|---|---|