百度地图点聚合仿链家定位点多级聚合,且滑动、刷新加载定位点

四个月前公司新项目,要求首页仿链家实现地图定位点多级聚合,效果图如下:

好吧,我们没效果图,暂时拿链家的效果图代替一下:

效果大概是这个样子,而我们要求比链家更深一级,当时看到这需求和效果,第一想法就是下载百度官方 demo,下载运行后发现很不适用,然后尝试着修改官方源码,结果从入门改到放弃......

然后,网上各种搜索,找了一天发现几乎没有这方面写的比较详细、实用的文章......

只能自己开辟思路写了,后来终于发现把问题想的太复杂了,被自己带到沟里去了,看似点聚合,实则是多点位标记。功能比较全,代码比较多,耐心看下去或许会有收获。不废话了,说一下解决方案:

一、先获取定位点,为了方便使用可以采用 sql 存储,然后根据 parentId 划分出定位点级别,这里就不普及 sql 的用法了,不会的自行百度,这里要注意判断经纬度是否为空:

//获得行政区
getEqpAreas(result);
//清空数据库
dbOperatorService.EmptyEQPAreas();
//添加数据库
dbOperatorService.SaveEQPAreas(areasList);

二、添加百度地图加载,很简单,但是这里要先有思路,根据自己需要展示几层聚合,设置好地图缩放的“级别段”,可能有些人会迷糊,这里简单普及一下;

1、百度地图好像一共21级别,级别越大,地图范围越小。级别越小,地图范围越大。

1级 :10000公里     2级:5000公里     3级:2000公里      4级:1000公里    5级:500公里      6级:200公里       7级:100公里

8级 : 50公里       9级:25公里            10级:20公里         11级:10公里       12级:5公里       13级:2公里         14级:1公里

15级:500米         16级:200米            17级:100米           18级:50米          19级:20米         20级:10米           21级:5米

大概是这个样子。

而在使用中前8级可以直接忽略,20、21级可以根据自己需求选择,好了,介绍完地图级别,就要说什么叫缩放“级别段”了。

要实现效果图中 “聚合点” 缩放样式,只能根据地图缩放等级来设置,先设置好地图缩放最小、最大级别,然后缩放深度有几层,就把地图展示级别分为几个层次,这个层次就叫“级别段”。怎么划分就看个人需求了。

2、添加地图展示,并设置最大、最小级别以及定位,这些就不科普了,不会的自行百度。

baiduMap = mapView.getMap();

//设置默认位置
LatLng latLng = new LatLng(30.280782,120.121143);
status = new MapStatus.Builder().target(latLng).zoom(11).build();

baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(status));

//是否显示控制地图等级缩小、放大按钮
mapView.showZoomControls(false);

//打开定位图层
baiduMap.setMyLocationEnabled(true);

//声明 LocationClient 类
client = new LocationClient(getContext());

//配置定位 SDK 参数
location();

//注册监听函数
client.registerLocationListener(listener);
//开启定位
client.start();
//图片点击事件,回到固定点
client.requestLocation();

//地图缩放等级
baiduMap.setMaxAndMinZoomLevel(21, 9);

三、把得到的定位点按等级分别添加到集合中,并且在地图上添加标记点,这里只举一层为例;

private void setOneMarker() {
    cityAreaList = new ArrayList<>();
    
    // 从 Sql 中取出对应等级的定位点 
    cityAreaList = dbOperatorService.GetEQPAreasOneGrade();

    if (cityAreaList != null && cityAreaList.size() > 0) {
        for (int i = 0; i < cityAreaList.size(); i++) {
            EQCityArea cityArea = cityAreaList.get(i);
            addMarket(cityArea);
        }
        
    } else {
        Toast.makeText(getContext(), "暂无标记点", Toast.LENGTH_SHORT).show();
    }

}

// 标记 Market
private void addMarket(EQCityArea cityArea) {

    if (AppUtil.isNotEmpty(cityArea.getLatitude()) && AppUtil.isNotEmpty(cityArea.getLongitude())) {

        Double lat = Double.valueOf(cityArea.getLatitude()) / 1000000;
        Double lon = Double.valueOf(cityArea.getLongitude()) / 1000000;

        String content = cityArea.getName();

        LatLng latLng = new LatLng(lat, lon);

        // 定位点样式根据自己需求设置
        View view = LayoutInflater.from(getContext()).inflate(R.layout.maptext_layout, null, false);
        TextView tv_adress = view.findViewById(R.id.tv_adress);
        TextView text = view.findViewById(R.id.text);
        text.setVisibility(View.GONE);
        tv_adress.setText(content);
        BitmapDescriptor descriptorOne = BitmapDescriptorFactory.fromView(view);

        MarkerOptions options = new MarkerOptions().icon(descriptorOne).position(latLng).zIndex(9)
                .animateType(MarkerOptions.MarkerAnimateType.grow);
        Marker markerOne = (Marker) baiduMap.addOverlay(options);
        markerOne.setVisible(false);

        markerOneList.add(markerOne);
        latLngOneList.add(latLng);
    }

第二层、第三层获取、添加标记同理。

四、很重要、很关键!添加地图状态发生改变时监听地图缩放等级,

baiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
    @Override
    public void onMapStatusChangeStart(MapStatus mapStatus) {
      
    }

    @Override
    public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
    
    }

    @Override
    public void onMapStatusChange(MapStatus mapStatus) {
      
    }

    @Override
    public void onMapStatusChangeFinish(MapStatus mapStatus) {

    }

五、在 onMapStatusChangeFinish() 方法中获取当前地图缩放等级,并且获取最后一级详细点位;

1、获取当前地图缩放级别以及手机当前屏幕地图中心点

// 获得当前地图等级

zoomSize = baiduMap.getMapStatus().zoom;

Log.e("Start", zoomSize + "");

// 获取屏幕中心点坐标

LatLng latLng = mapStatus.target;

Log.e("", latLng + "");

2、根据自己设定的最大地图级别进行判断,这里根据个人需求,如果聚合最后一级和链家一样要求滑动加载某个点的详情,就添加是否大于缩放最大级别的判断,如果只是缩放,只需要添加是否小于缩放最大级别的判断就行了:

@Override
public void onMapStatusChangeFinish(MapStatus mapStatus) {

    // 获得当前地图等级
    zoomSize = baiduMap.getMapStatus().zoom;
    Log.e("Start", zoomSize + "");

    // 获取屏幕中心点坐标
    LatLng latLng = mapStatus.target;
    Log.e("", latLng + "");
    if (zoomSize > MAPSIZE_EIGHTEEN) {  //当当前地图级别大于 18 时
        if (baiduMap.getProjection() != null) {

            //获取经纬度区域内监控
            getMonitor(latLng);
            //获取经纬度区域内社会资源
            getResourcesByLatLng(latLng);
        }
    } else if (zoomSize <= MAPSIZE_EIGHTEEN) { //当当前地图级别小于 18 时

        // 如果详细点点击有气泡加上这句去气泡,如果没有就不用写这句
        baiduMap.hideInfoWindow();

        //监控点
        if (markerPoint != null && markerPoint.size() > 0) {
            for (int i = 0; i < markerPoint.size(); i++) {
                markerMoni = markerPoint.get(i);
                markerMoni.setVisible(false);
            }
        }

        //社会资源
        if (resourMarkerList!=null&&resourMarkerList.size()>0){
            for (int i = 0; i < resourMarkerList.size(); i++) {
                resourMaker = resourMarkerList.get(i);
                resourMaker.setVisible(false);
            }
        }


        if (view != null) {
            if (view.getVisibility() == View.VISIBLE) {
                view.setVisibility(View.GONE);
            }
        }

        // 为了防止异常,把集合清空一下
        if (monitorList != null && monitorList.size() > 0) {
            monitorList.clear();
        }
        if (monitorSet != null && monitorSet.size() > 0) {
            monitorSet.clear();
        }
        if (markerPoint != null && markerPoint.size() > 0) {
            markerPoint.clear();
        }
        if (publicResourceList !=null && publicResourceList.size()>0){
            publicResourceList.clear();
        }

        if (resourceHashSet!=null&&resourceHashSet.size()>0){
            resourceHashSet.clear();
        }

    }

    if (baiduMap.getProjection()!=null){
        //获取屏幕中心点
        updateMapState();
    }
}

六、在 updateMapState() 方法中通过获取当前屏幕地图范围最大值展示标记点,防止同时标记过多出现屏幕卡顿,并通过判断地图级别段对 Marker 的展示进行控制:

1、获取屏幕地图范围

WindowManager manager = getActivity().getWindowManager();

DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);

//获取屏幕的宽和高
int width = metrics.widthPixels;
int height = metrics.heightPixels;

Point point = new Point();
point.x = 0;
point.y = 0;
final LatLng llL = baiduMap.getProjection().fromScreenLocation(point);//左上角经纬度
Log.e("", llL + "");

Point ptR = new Point();
ptR.x = width;
ptR.y = height;
final LatLng llR = baiduMap.getProjection().fromScreenLocation(ptR);//右下角经纬度
Log.e("", llR + "");

2,先判断每一层的定位点是否在屏幕坐标范围内,在内就展示,不在就隐藏。另外根据缩放级别选择展示哪一层,隐藏哪一层,这里以第一层和第二层举个例子:

先把变量给出来,不然不太好懂:

//第一层聚合
Marker markerOne;
private List<EQCityArea> cityAreaList;
private List<Marker> markerOneList = new ArrayList<>();
private List<LatLng> latLngOneList = new ArrayList<>();
//第二层
Marker markerTwo;
private List<EQStreet> streetList;
private List<Marker> markerTwoList = new ArrayList<>();
private List<LatLng> latLngTwoList = new ArrayList<>();

开始进行判断:

if (zoomSize <= MAPSIZE_TWELVE) { //  小于 12 级别

    if (latLngOneList != null && latLngOneList.size() > 0) {
        for (int i = 0; i < latLngOneList.size(); i++) {
            LatLng latLng = latLngOneList.get(i);
            Double lat = latLng.latitude;
            Double lon = latLng.longitude;

            if (llR.latitude < lat && lat < llL.latitude && llL.longitude < lon && lon < llR.longitude) {
                markerOne = markerOneList.get(i);
                markerOne.setVisible(true);
            } else {
                markerOne = markerOneList.get(i);
                markerOne.setVisible(false);
            }
        }

        if (markerTwoList != null && markerTwoList.size() > 0) {
            for (int i = 0; i < markerTwoList.size(); i++) {
                markerTwo = markerTwoList.get(i);
                markerTwo.setVisible(false);
            }
        }

        if (markerThreeList != null && markerThreeList.size() > 0) {
            for (int i = 0; i < markerThreeList.size(); i++) {
                markerThree = markerThreeList.get(i);
                markerThree.setVisible(false);
            }
        }

    } else { //如果第一层没数据

        if (latLngTwoList != null && latLngTwoList.size() > 0) {
            for (int i = 0; i < latLngTwoList.size(); i++) {
                LatLng latLng = latLngTwoList.get(i);
                Double lat = latLng.latitude;
                Double lon = latLng.longitude;

                if (llR.latitude < lat && lat < llL.latitude && llL.longitude < lon && lon < llR.longitude) {
                    markerTwo = markerTwoList.get(i);
                    markerTwo.setVisible(true);
                } else {
                    markerTwo = markerTwoList.get(i);
                    markerTwo.setVisible(false);
                }
            }
        }

        if (markerOneList != null && markerOneList.size() > 0) {
            for (int i = 0; i < markerOneList.size(); i++) {
                markerOne = markerOneList.get(i);
                markerOne.setVisible(false);
            }
        }

        if (markerThreeList != null && markerThreeList.size() > 0) {
            for (int i = 0; i < markerThreeList.size(); i++) {
                markerThree = markerThreeList.get(i);
                markerThree.setVisible(false);
            }
        }
    }
} else if (zoomSize > MAPSIZE_TWELVE && zoomSize <= MAPSIZE_FIFTEEN) {// 12 到 15

    if (latLngOneList != null && latLngOneList.size() > 0) {

        if (latLngTwoList != null && latLngTwoList.size() > 0) {
            for (int i = 0; i < latLngTwoList.size(); i++) {
                LatLng latLng = latLngTwoList.get(i);
                Double lat = latLng.latitude;
                Double lon = latLng.longitude;

                if (llR.latitude < lat && lat < llL.latitude && llL.longitude < lon && lon < llR.longitude) {
                    markerTwo = markerTwoList.get(i);
                    markerTwo.setVisible(true);
                } else {
                    markerTwo = markerTwoList.get(i);
                    markerTwo.setVisible(false);
                }
            }
        }

        if (markerOneList != null && markerOneList.size() > 0) {
            for (int i = 0; i < markerOneList.size(); i++) {
                markerOne = markerOneList.get(i);
                markerOne.setVisible(false);
            }
        }

        if (markerThreeList != null && markerThreeList.size() > 0) {
            for (int i = 0; i < markerThreeList.size(); i++) {
                markerThree = markerThreeList.get(i);
                markerThree.setVisible(false);
            }
        }
    } 

七、写到这里通过手指缩放屏幕,聚合功能已经可以展示出来了,但是并不完美,作为程序狗,我们要省事,所以我们还需要再添加一个功能,当用户点击最外层聚合点时间直接进入下一层,这里就要用到 Marker 点击事件了,这里如果你只有聚合功能只需要要控制增加地图层次级别就好了:

baiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
    @Override
    public boolean onMarkerClick(Marker marker) {

        if (zoomSize < 18) {

            zoomSize += 3; // 3 是我的地图级别段长度,根据自己设置的填写 
            status = new MapStatus.Builder().zoom(zoomSize).target(marker.getPosition()).build();
            baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(status));

        }
    }
 }

当然大多数功能并不会这么简单,往往需求还会让点击定位点弹出气泡:

if (zoomSize < 18) {

    zoomSize += 3;
    status = new MapStatus.Builder().zoom(zoomSize).target(marker.getPosition()).build();
    baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(status));

} else {

    // 填写自己点击气泡要展示的 View

 // 创建 InfoWindow , 传入 View 、 Latlng 、Y 轴偏移量
    InfoWindow window = new InfoWindow(view, marker.getPosition(), -80);
    baiduMap.showInfoWindow(window);

}

八,最后再来讲解一下,怎么仿链家滑动屏幕加载新数据,并且不重复加载老数据,这里就要用到 Set 集合:

1、先是在设置实体类是添加 

public boolean equals(Object o) {}
public int hashCode() {}

2、先把获取到的定位点添加到 ArrayList 集合中,再遍历集合中的定位点是不是在屏幕范围内,在就添加到 Set 集合中,然后根据 Set 集合添加 Marker:

// 把获取到的点添加到 ArrayList 集合中
resourceList.add(resource);
// 判断点是否在屏幕内

WindowManager manager = getActivity().getWindowManager();

DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);

//获取屏幕的宽和高
int width = metrics.widthPixels;
int height = metrics.heightPixels;

Point point = new Point();
point.x = 0;
point.y = 0;
llL = baiduMap.getProjection().fromScreenLocation(point);//左上角经纬度
Log.e("", llL + "");

Point ptR = new Point();
ptR.x = width;
ptR.y = height;
llR = baiduMap.getProjection().fromScreenLocation(ptR);//右下角经纬度


Set<MoniPoint> resourceSet = new HashSet<>();

if (resourceList!=null&&resourceList.size()>0){
    for (int i=0;i<resourceList.size();i++){
        Social resource = resourceList.get(i);
        Double lat = Double.valueOf(resource.getLatitude())/1000000;
        Double lon = Double.valueOf(resource.getLongitude())/1000000;

        if (llR.latitude < lat && lat < llL.latitude && llL.longitude < lon && lon < llR.longitude) {

            boolean isPoint = resourceHashSet.contains(resource);
            if (isPoint) {

            } else{
                resourceHashSet.add(resource);
                Log.e("",resourceHashSet.size()+"");

                // 添加绘制 Marker 的方法
                drawResource(resource);
            }
        }
    }
}
private void drawResource(Social resource) {

    publicResourceList.add(resource);

    Double lat = Double.valueOf(resource.getLatitude())/1000000;
    Double lon = Double.valueOf(resource.getLongitude())/1000000;

    LatLng latLng = new LatLng(lat, lon);

    BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.drawable.icon_shehuizy_map);

    MarkerOptions options = new MarkerOptions().icon(descriptor).position(latLng).zIndex(9)
            .animateType(MarkerOptions.MarkerAnimateType.grow);
    Marker marker = (Marker) baiduMap.addOverlay(options);
    marker.setVisible(true);
    resourMarkerList.add(marker);

    Log.e("",resourMarkerList.size()+"");
}

九、打完收工,第一次写这么长的博客,虽然写的比较乱,但真的用心了!有什么不懂的可以问我,希望可以帮助那些找不到解决方案的伙伴。如果文章对你有用,请点个赞!

最后,最近发现很多朋友要demo,可能写的比较杂乱,看起来难以理解,所以写了个小demo,本想设置1积分下载,但是发现现在系统起步默认5积分,需要下载的朋友自己视情况下载吧,demo下载地址:

https://download.csdn.net/download/baidu_36600645/11223113

 

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
要在Vue中实现百度地图聚合,可以按照以下步骤进行操作: 1. 首先,在Vue项目中安装百度地图的JavaScript API。可以通过在`index.html`文件中添加以下代码来引入百度地图的API: ```html <script type="text/javascript" src="https://api.map.baidu.com/api?v=2.0&ak=YOUR_API_KEY"></script> ``` 确保替换`YOUR_API_KEY`为你自己的百度地图API密钥。 2. 在Vue组件中创建地图容器,并初始化地图。可以在`mounted`钩子函数中添加以下代码: ```javascript mounted() { const map = new BMap.Map("map-container"); // 创建地图实例 const point = new BMap.Point(经度, 纬度); // 设置地图中心坐标 map.centerAndZoom(point, 15); // 初始化地图,设置地图缩放级别 this.map = map; // 将地图实例保存到组件数据中 } ``` 确保替换`经度`和`纬度`为你希望地图显示的中心坐标。 3. 获取需要聚合标记数据,并使用百度地图的`MarkerClusterer`类进行聚合。可以在`mounted`钩子函数中添加以下代码: ```javascript mounted() { // ... const markers = []; // 存储标记的数组 // 添加标记到地图和markers数组中 yourData.forEach((item) => { const point = new BMap.Point(item.lng, item.lat); const marker = new BMap.Marker(point); map.addOverlay(marker); markers.push(marker); }); // 创建聚合器并设置参数 const markerClusterer = new BMapLib.MarkerClusterer(map, { markers: markers, }); // ... } ``` 确保替换`yourData`为你的标记数据数组,每个标记的经度和纬度分别存储在`item.lng`和`item.lat`中。 4. 在Vue组件中添加地图容器的HTML代码。可以在组件模板中添加以下代码: ```html <template> <div id="map-container" style="width: 100%; height: 400px;"></div> </template> ``` 确保根据需要设置地图容器的宽度和高度。 通过以上步骤,你就可以在Vue项目中实现百度地图聚合效果了。记得在百度地图开放平台申请并获取到API密钥,并替换代码中的`YOUR_API_KEY`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值