百度地图大部分API是参照谷歌来制作的,两者的API大部分是相似的(iOS&Android情况都一样)。本章内容记录一下两个地图如何添加自定义大头针。
百度地图iOS版本
百度地图iOS版称标注点为大头针BMKAnnotationView,该类有以下几个重要属性。
///气泡
@property (nonatomic, strong)BMKActionPaopaoView* paopaoView;
///annotation view显示的图像
@property (nonatomic, strong) UIImage *image;
///显示在气泡左侧的view(使用默认气泡时,view的width最大值为32,height最大值为41,大于则使用最大值)
@property (strong, nonatomic) UIView *leftCalloutAccessoryView;
///显示在气泡右侧的view(使用默认气泡时,view的width最大值为32,height最大值为41,大于则使用最大值)
@property (strong, nonatomic) UIView *rightCalloutAccessoryView;
从上面属性可以看出BMKAnnotationView只能对几张图片进行填充,没办法实现较为复杂的视图,如果还要实现点击不同视图触发不同事件那么更为麻烦,有的需求不可以实现,有的需求可以实现,就算可以实现,也会使代码分散,达不到高内聚的标准。
我理想中的实现方式应该是这样的:像普通自定义View一样,所有的UI布局和事件监听都存放在一个头文件和一个实现文件里面,然后该标注点可以随着地图的移动而移动,流畅顺滑不卡顿。直接上代码:
- (void)updateLocViewPosistion{
for (NSDictionary *dict in self.locLatlngs) {
CLLocationCoordinate2D coor;
coor.latitude = 22;
coor.longitude = 113;
BPLocView *locView = [[[UINib nibWithNibName:@"BPLocView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
//将经纬度转换成屏幕坐标
CGPoint point = [self.mapView convertCoordinate:coor toPointToView:self.view];
locView.center = point;
}
}
#pragma mark - BMKMapViewDelegate
/**
*地图渲染每一帧画面过程中,以及每次需要重绘地图时(例如添加覆盖物)都会调用此接口
*@param mapview 地图View
*@param status 此时地图的状态
*/
-(void)mapView:(BMKMapView *)mapView onDrawMapFrame:(BMKMapStatus *)status{
[self updateLocViewPosistion];
}
/**
*将经纬度坐标转换为View坐标
*@param coordinate 待转换的经纬度坐标
*@param view 指定相对的View
*@return 转换后的View坐标
*/
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view;
该方法为 BMKMapView 的实例方法。
利用BMKMapView提供的坐标转换实例方法以及BMKMapViewDelegate协议中的onDrawMapFrame刷帧方法可以实现我们的需求。
百度地图Android版本
百度地图Android版称标注点为Marker,局限性参照百度地图iOS版本小节中的说法。
解决思路也是和百度地图iOS版本一致,直接上代码:
private BaiduMap mBaiduMap;
/** 地图坐标转换 */
private Projection mProjection;
@Override
public void onMapLoaded() {
MLog.d("Baidu Map onMapLoaded");
mProjection = mBaiduMap.getProjection();
}
@Override
public void onMapDrawFrame(GL10 gl10, MapStatus arg1) {
updateLocViewLocations();
}
protected void updateLocViewLocations() {
for (int i = 0; i < locViews.size(); i++) {
MLocationCover cover = locViews.get(i);
//地理坐标转屏幕坐标
Point point = mProjection.toScreenLocation(MapUtil.converLatLng(cover.latLng));
cover.setX(point.x);
cover.setY(point.y);
}
}
与iOS版本有一点小差别的是坐标转换方法不是BaiduMap这个类的实例方法,而是它的Projection类的一个实例方法。
谷歌地图iOS版本
谷歌地图iOS版称标注点为GMSMarker,局限性和解决方法和上面的百度地图iOS版相似,直接上代码:
#pragma mark - private method
- (void)updateLocViewPosistion{
for (NSDictionary *dict in self.locLatlngs) {
CLLocationCoordinate2D coor;
coor.latitude = 22;
coor.longitude = 113;
BPLocView *locView = [[[UINib nibWithNibName:@"BPLocView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
//地理坐标转屏幕坐标
CGPoint point = [self.mapView.projection pointForCoordinate:coor];
locView.center = point;
}
}
#pragma mark - GMSMapViewDelegate
-(void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position{
[self updateLocViewPosistion];
}
坐标转换方法是在GMSProjection类中,如下:
@interface GMSProjection : NSObject
/** 将经纬度坐标转换成屏幕坐标*/
- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate;
这里与百度地图iOS版本有所区别的就是刷帧方法的名字是这个:
@protocol GMSMapViewDelegate<NSObject>
- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position;
@end
其它思路如百度地图iOS版中描述的,这里就不再重复解释。
谷歌地图Android版本
谷歌地图Android版称标注点为Marker,局限性和解决方法和上面的百度地图iOS版相似,直接上代码:
private GoogleMap mGoogleMap;
private Projection getProjection() {
if (mGoogleMap == null) {
return null;
}
return mGoogleMap.getProjection();
}
@Override
public void onCameraMove() {
updateLocViewLocations();
}
protected void updateLocViewLocations() {
for (int i = 0; i < locViews.size(); i++) {
MLocationCover cover = locViews.get(i);
//地理坐标转屏幕坐标
Point point = getProjection().toScreenLocation(latlng);
cover.setX(point.x);
cover.setY(point.y);
}
}
这次没有在onMapLoad()中给mProjection赋值,可能是当初在onMapLoad中获取到的mProjection为null,所以改成懒加载机制。其它思路百度地图iOS版本类似,这里就不重复。