继续来总结百度地图。
前面我们将marker传入了地图中去,但是,随着项目的深入,需要在地图上显示的marker也越来越多,这个时候就必然会出现一个问题:卡顿!
那么百度地图也为我们提供了“点聚合”来解决这个问题,不过我们还可以设置地图只显示屏幕范围内的marker来解决这个问题。由于我项目中的marker实在太多了,全部展现出来有几千个marker,于是两个一起都用了,结合在一起,效果还是不错的,但是在marker比较集中的时候,在缩放时由聚合到marker的计算过程还是会有一点卡顿,因为整个屏幕同时有上百个marker从聚合里散落出来。不知道有没有大神提出好的方法,欢迎留言!
那么现在我们开始第一部分——点聚合:
点聚合这一部分百度是开源了,所以下载的sdk里是没有这部分代码,我们可以去下载demo,从demo里把clusterutil文件夹全部拷到自己的工作目录下:
然后呢,我们拿到点聚合的管理类:
/**
* 点聚合功能
*/
public ClusterManager mClusterManager;
// 定义点聚合管理类ClusterManager
mClusterManager = new ClusterManager<>(context, mBaiduMap,this);
// 设置地图状态监听,当地图状态发生改变时,进行点聚合运算
mBaiduMap.setOnMapStatusChangeListener(mClusterManager);
mBaiduMap.setOnMarkerClickListener(mClusterManager);//点聚合marker的点击事件
然后是MyItem
/**
* 每个Marker点,包含Marker点坐标以及图标
*/
public class MyItem<T extends MapBean> implements ClusterItem<T> {
private LatLng mPosition;
private T info;
@Override
public LatLng getPosition() {
return mPosition;
}
public MyItem(LatLng latLng, T info) {
mPosition = latLng;
this.info = info;
}
//marker的布局View:这里我依旧用上一篇中marker的布局
@Override
public BitmapDescriptor getBitmapDescriptor() {
return getView(info);
}
//每一个点的信息
@Override
public T getMapBean() {
return info;
}
}
然后是getView()方法:
private <T extends MapBean> BitmapDescriptor getView(T info) {
ViewHolder viewHolder;
if (info instanceof DBuildingInfo) {
//buildingInfo
if (view == null) {
view = View.inflate(context, R.layout.item_baidumap_marker, null);
viewHolder = new ViewHolder();
viewHolder.tvDbiName = (TextView) view.findViewById(tv_dbiName);
viewHolder.tvName = (TextView) view.findViewById(R.id.tv_duiName);
viewHolder.imgMarker = (ImageView) view.findViewById(R.id.img_Marker);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
...
//这里做一些赋值等操作
...
}
return BitmapDescriptorFactory.fromView(viewOut);
}else {
return null;
}
}
从这里可以看到,使用点聚合,我不需要再去写添加单个marker的操作,这些操作在开源的代码中,已经为我们做好了,我们只需要把需要添加的marker的经纬度及信息给它就可以了,所以我们查询到我们要添加marker的数据后,直接调用这个方法:
//单位建筑覆盖物标志
public void addMarker(List list) {
if (list != null && list.size() > 0) {
List items = new ArrayList<>();
for (T info : list) {
String[] ss = info.getMapPosition().split(",");
LatLng latLng = new LatLng(new Double(ss[1]), new Double(ss[0]));
items.add(new MyItem(latLng, info));
}
mClusterManager.addItems(items);
}
}
这样基本就完成了,里面的添加marker及点聚合的运算,百度已经做好了。
2.显示屏幕范围内的点:
首先,我们要去获取屏幕的两个对角点,然后再得到他们的经纬度,这样我们就能得到一个矩形地图范围了
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
int height = outMetrics.heightPixels;
Point ptL = new Point();
ptL.x = 0;
ptL.y = 0;
final LatLng llL = mBaiduMap.getProjection().fromScreenLocation(ptL);//左上角经纬度
Point ptR = new Point();
ptR.x = width;
ptR.y = height;
final LatLng llR = mBaiduMap.getProjection().fromScreenLocation(ptR);//右下角经纬度
然后只要去判断该经纬度坐标是否在这个屏幕内:
infos =new ArrayList<>();
String[] latlngs = info.getDbiMapposition().split(",");
double lat = new Double(latlngs[1]);
double lng = new Double(latlngs[0]);
if (llr.latitude < lat && lat < ll.latitude && ll.longitude < lng && lng < llr.longitude) {
infos.add(info);
}
这样,我们就可以调用addmarker()方法了:
mClusterManager.clearItems();//清理所有的items
addMarker(buildingInfos);
然后,屏幕移动了之后,我们需要重新去得到移动后的屏幕内的地图矩形坐标及当前范围内的marker,然后也重新进行点聚合运算,在点聚合类的管理类ClursterManger中,对地图状态监听的回调里,我们只需要在finish时候修改:
@Override
public void onMapStatusChangeFinish(MapStatus mapStatus) {
//移动完成后
mapUtil.updateMapState(mMap);
cluster();//重新进行点聚合运算
}
最后,当我们修改了查询条件时,重新查询出来的数据,这个时候,我的地图是没有移动,没有缩放的,也就不会有监听回调,所有在我们查询到了数据之后再去执行一边点聚合的运算,调用:
cluster();
MapBean:
用当前marker数据的bean来实现MapBena
public interface MapBean {
String getMapPosition();//经纬度
...
}
然后在点击事件中就可以直接这样:
点聚合的点击事件
mapUtil.mClusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener() {
@Override
public boolean onClusterClick(final Cluster cluster) {
for (BaiduMapUtil.MyItem item : cluster.getItems()) {//去除myitems
if (item.getMapBean() instanceof XXXXXInfo) { //判断取出的这个bean是否是我marker数据的bean
...自己的操作...
}
}
return false;
}
});
当item的点击事件
@Override
public boolean onClusterItemClick(ClusterItem item) {
if (item.getMapBean() instanceof DBuildingInfo) {
...当前自己的操作...
}
return false;
}
由于现在marker是源码中加的,那么有些关于marker的设置,我们可以重新到DefaultClusterRenderer类中的perform(MarkerModifier markerModifier)中根据我们的需求进行设置:
private void perform(MarkerModifier markerModifier) {
// Don't show small clusters. Render the markers inside, instead.
......
onBeforeClusterItemRendered(item, markerOptions);
marker = mClusterManager.getMarkerCollection().addMarker(markerOptions);
//添加下面
marker.setZIndex(14);//设置marker在级别
marker.setAnchor(0.5f,0.5f);//设置marker的中心点
//添加上面
markerWithPosition = new MarkerWithPosition(marker);
......
}
以上!
这个方法在marker比较密集的情况下,放大后,在进行聚合运算的时候还是会有点卡顿,哪位老司机有更好的方法?