百度地图SDK Android版开发 9 覆盖物示例3批量点、海量点、点聚合

前言

前文介绍了如何在地图上添加一个Overlay,本文重点介绍如何批量添加和删除海量点点聚合的功能。

  • 批量操作:一次性向地图上大批量添加Overlay的接口和一次性清除地图上的所有覆盖物(Overlay对象和infoWindow)的接口。
  • 海量点:支持海量点图层绘制,用于批量展现坐标点数据,并支持点击事件。
  • 点聚合:支持通过缩小地图层级,将定义范围内的大量标注点聚合显示成一个标注点。

相关的类和接口

批量添加和删除

百度地图BaiduMap地图类除了提供添加一个覆盖物的接口外,还提供了批量添加和删除的接口:

  • addOverlay接口可以向地图添加点、线、面、弧、圆和文本覆盖物。
  • addOverlays接口可以一次性向地图上添加大批量的点、线、面等覆盖物。
  • clear接口则一次性清除地图上的所有覆盖物(Overlay对象和infoWindow)。
  • setOnMarkerClickListenerremoveMarkerClickListener接口可以添加和移除Marker单击事件。
类型方法说明
OverlayaddOverlay(OverlayOptions options)向地图添加一个 Overlay
List< Overlay >addOverlays(List< OverlayOptions > options)向地图添加多个 Overlay
voidclear()清空地图所有的 Overlay 覆盖物以及 InfoWindow
voidsetOnMarkerClickListener(BaiduMap.OnMarkerClickListener listener)设置地图 Marker 覆盖物点击事件监听者
自3.4.0版本起可设置多个监听对象,
停止监听时调用removeMarkerClickListener移除监听对象
voidremoveMarkerClickListener(BaiduMap.OnMarkerClickListener listener)移除一个地图 Marker 覆盖物点击事件监听者

海量点

MultiPoint海量点覆盖物,通过MultiPointOption类来设置海量点图层的属性。

  • 部分覆盖物类关系图:
Marker
Overlay
MultiPoint
Polyline
Polygon
Arc
Circle
Text
  • 部分覆盖物选项类关系图:
MarkerOptions
OverlayOptions
MultiPointOption
PolylineOptions
PolygonOptions
ArcOptions
CircleOptions
TextOptions

BaiduMap类

百度地图SDKBaiduMap地图类与海量点相关的接口:

  • addOverlay接口可以向地图添加海量点。

  • setOnMultiPointClickListener接口设置海量点单击事件

类型方法说明
voidsetOnMultiPointClickListener(BaiduMap.OnMultiPointClickListener listener)设置地图 MultiPoint 覆盖物点击事件监听者

BaiduMap.OnMultiPointClickListener接口

// 地图MultiPoint覆盖物点击事件监听接口
public interface OnMultiPointClickListener {
    /**
     * 地图 MultiPoint 覆盖物点击事件监听函数
     * @param point 被点击的 MultiPoint
     * @param item 被点击的 MultiPointItem
     * @return
     */
    boolean onMultiPointClick(MultiPoint point, MultiPointItem item);
}

MultiPointOption 海量点选项

  • getter
类型方法说明
BitmapDescriptorgetIcon()获取 MultiPoint 覆盖物图标
List< MultiPointItem >getMultiPointItems()获取 MultiPoint 覆盖物数据集合
floatgetAnchorX()获取 MultiPoint 覆盖物水平方向锚点比例
floatgetAnchorY()获取 MultiPoint 覆盖物垂直方向锚点比例
intgetPointSizeHeight()获取 MultiPoint 覆盖物纹理点的高度
intgetPointSizeWidth()获取 MultiPoint 覆盖物纹理点的宽度
booleanisVisible()获取MultiPoint 覆盖物可见性
  • setter
类型方法说明
MultiPointOptionsetIcon(BitmapDescriptor icon)设置 MultiPoint 覆盖物的图标 (必填)
MultiPointOptionsetMultiPointItems(List< MultiPointItem > multiPointItems)添加海量点数据集合(必填)
MultiPointOptionsetPointSize(int pointSizeWidth, int pointSizeHeight)纹理渲染大小,默认为icon图片大小
MultiPointOptionsetAnchor(float anchorX, float anchorY)设置 MultiPoint 覆盖物的锚点比例,
默认(0.5f, 0.5f)水平居中,垂直下对齐
MultiPointOptionsetClickable(boolean isClickable)设置MultiPoint是否可点击
MultiPointOptionvisible(boolean visible)设置MultiPoint 覆盖物可见性,默认 true 显示

MultiPointItem 海量点单个点对象

类型方法说明
MultiPointItem(LatLng point)MultiPoint覆盖物单个点构造函数
LatLnggetPoint()获取MultiPoint覆盖物单个点经纬度
StringgetTitle()获取MultiPoint覆盖物单个点标题
voidsetTitle(String title)设置MultiPoint覆盖物单个点标题

点聚合

百度地图SDK点聚合部分已开放源码,位于Democlusterutil包中,可以下载后自行修改使用。

相关代码文件清单:

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

示例

界面布局

在这里插入图片描述

  • 布局文件
<?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.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类

  • 以下是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;
        }
    }
}
批量点
  • 创建OverlayOptions的集合
  • 在地图上批量添加覆盖物
  • 设置Marker单击事件
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);
}
海量点
  • 加载大量点数据(参考自官网示例Demo)
  • 设置海量点数据
  • 添加海量点覆盖物
  • 设置海量点单击事件
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类

  • 以下是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);
}

运行效果图

批量点海量点点聚合
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值