美文网首页租房iOS程序猿iOS Developer
百度地图、谷歌地图添加自定义大头针视图

百度地图、谷歌地图添加自定义大头针视图

作者: Little_Mango | 来源:发表于2017-02-22 17:56 被阅读1398次

    百度地图大部分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版本类似,这里就不重复。

    相关文章

      网友评论

      • b3aebe49fe2a:有没有谷歌的Demo 看不太明白发我一个呗 2656533057
      • Clemo:用了GMSMarker添加了标注,加入了点击标注弹出自定义视图,但是这个视图里面的控件无法点击,无法解决这个问题. 谷歌地图也无法加入MKAnnotation. 查了很久还是没能解决.请教一下!
        Little_Mango:@Clemo SDK不支持popView内部的点击事件,要么被过滤了,要么被覆盖了。我在stackOverFlow看到的解决方案大多和我这边文章的一致,自己自定义一个popView,加载到mapView.superView中,在markerInfoWindow事件中显示,在didChangeCameraPosition中刷新popView的位置,在didTapAtCoordinate隐藏。
        Clemo:@Little_Mango 不是的- (UIView *GMS_NULLABLE_PTR)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker 用这个方法返回的自定义弹出视图. 然后这个视图只能在- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker方法里面回调点击事件. 这个自定义视图直接添加手势都无法点击里面的按钮也无法点击.所以我觉得应该是拦截了这个自定义视图的点击或者说是超出了父视图
        Little_Mango:你的自定义视图还是GMSMarker,然后只是将GMSMarker的iconView属性替换掉?如果是这样那么你而事件是被Map的代理方法消费了,iOS没有拦截事件这一说法,估计是GMSMarker的iconView被包装了一层事件或者你的事件在-hitTest被忽略了。

      本文标题:百度地图、谷歌地图添加自定义大头针视图

      本文链接:https://www.haomeiwen.com/subject/brymwttx.html