美文网首页
ios高德地图 custom annotaionView 用法

ios高德地图 custom annotaionView 用法

作者: 姬歌 | 来源:发表于2018-01-22 15:11 被阅读358次

    本文解决annotationView重叠时响应问题、未选中与选中状态下annotationView尺寸变化、标签变化问题。
    按照官方给的api,实现简单的展示annotation本来是很简单的,但是要加一些自定义内容,就很变态了,毕竟只能继承他的AnnotationView,看不到实现源码,很多特性都要去摸索!

    我们的需求是,地图上有一个人员集合,每个人有姓名-name,电话phone。要求默认状态是小头像+顶部name;点击后选中,变为大头像+顶部name&phone,选中后点击电话号码要弹出拨号AlertSheet。


    图1、未选中 图2、选中

    刚开始我是把label和icon通过代码生成一个图片,但是发现图片中name很模糊;找网上找了不少办法还是做不出高清文字。加上做成图片,没办法区分点击了icon还是name,所以放弃了这种办法。

    最后参照官方Demo,使用CustomAnnotationView。(这不能用气泡callout,因为不选中的时候也要显示一个label)

    Demo中是自定义calloutView,每次需要显示、隐藏就在setSelected内removeFromSuperView,addSubView去修改UI。我是在init方法里面全部初始化UI,然后在setSelected方法内,调用自定义方法annoLayoutSubViews去修改icon大小,label的大小、label的内容,最后修改整个CustomAnnotationView大小。可能是因为修改了CustomAnnotationView的frame,导致了每次点击后,地图上被点击的annoView就消失不见了,用手势缩放地图后,它才被显示出来。于是我想了一个办法,在setSelected里面添加了一个回调selectCallback。在回调里面缩放地图。

    annotationView?.zIndex = theAno.zIndex
    annotationView?.selectCallback = {
                    annoisSelected, annoCoor in
                    self.zoomCount += 1
                    self.zoomQueue()
                    if annoisSelected {
                        self.mapCenter = annoCoor
                    }
                }
    
    func setMapCenterForCoor(_ coor: CLLocationCoordinate2D) {
            zoomMap()
            self.aMapView.setCenter(coor, animated: true)
        }
        
        func zoomMap() {
            let zl = self.aMapView.zoomLevel
            let defaultFocusZoom = 15.0
            if zl < defaultFocusZoom {
                self.aMapView.zoomLevel = defaultFocusZoom + 0.1
            }else {
                self.aMapView.zoomLevel = defaultFocusZoom - 0.1
            }
        }
        //zoomQueue的目的是在短时间的,不管有多少个selectCallback,都只对地图做一次缩放
        func zoomQueue() {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                self.zoomCount -= 1
                if self.zoomCount == 0 {
                     self.setMapCenterForCoor(self.mapCenter)
                }else if self.zoomCount < 0 {
                    self.zoomCount = 0
                }
            }
        }
    

    开发中遇到另外一个问题是,每个annoView的所属区域为图2所示红色框范围。label(name+phone)之上,我添加了button,可以监测到点击事件,并进行block回调。但是点击已选中的annView的黄色区域,是没有任何响应的!点击红色区域,高德内部会执行- (void)setSelected:(BOOL)selected animated:(BOOL)animated方法。当有两个annoView重叠时,点击上方的annoView的黄色区域(透明的),下方的annoView是不会响应的!!!测试大哥就说:不行!于是我只能在annoView内重写了下面的方法:

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            let iconOrigin = self.iconView.frame.origin
            let iconSize = self.iconView.frame.size
            let suprInside = super.point(inside: point, with: event)
            if isSelected {
                if suprInside {
                    if point.x >  iconOrigin.x &&
                        point.x < iconOrigin.x + iconSize.width &&
                        point.y > iconOrigin.y &&
                        point.y < iconOrigin.y + iconSize.height{
                        //点击了 icon图片
                    }else if point.y > iconOrigin.y {
                        //点击了 icon 左右两侧(黄色区域)
                        DispatchQueue.main.async {
                            if Date().timeIntervalSince(self.lastPointTestDate) > 0.1 {
                                debugPrint("~~~~~~点击了 icon 左右两侧~~~~~~")
                                self.tapInside!(point)
                            }
                            self.lastPointTestDate = Date()
                        }
                    }
                }
            }else {
    //            debugPrint("~~~~~not selected~~~~~~~")
            }
            return suprInside
        }
    

    再在回调方法中,重新判断到底应该选中哪一个annoView

    annotationView?.tapInside = {
                    point in
                    let pointInMap = annotationView?.convert(point, to: self.aMapView)
                    self.selectAnnoAtPoint(point: pointInMap!, exceptAnno: theAno)
                }
    
    func selectAnnoAtPoint(point: CGPoint, exceptAnno: XXXAnotation) {
            
            let assumeUnselectedAnnoIconSize = CGSize(width: CGFloat(36.0), height: CGFloat(53.0))
            let assumeUnselectedAnnoIconY: CGFloat = 25.0
            
            for i in 0..<anotationArray.count {
                let index = anotationArray.count-i - 1
              //设置了annoView.zIndex,大值在上,默认为0。
              //倒叙取anno,从最上方的anno判断其对应的annoView是否处于被点击范围内
                let annotation = anotationArray[index]
                if annotation != exceptAnno {
                    let annotationCenter = aMapView.convert(annotation.coordinate, toPointTo: aMapView)
                    
                    let annoIconX = annotationCenter.x - assumeUnselectedAnnoIconSize.width/2.0
                    let annoIconY: CGFloat = annotationCenter.y - (assumeUnselectedAnnoIconSize.width + assumeUnselectedAnnoIconY)/2.0 + assumeUnselectedAnnoIconY
                    
                    if point.x > annoIconX &&
                        point.x < annoIconX + assumeUnselectedAnnoIconSize.width &&
                        point.y > annoIconY &&
                        point.y < annoIconY + assumeUnselectedAnnoIconSize.height {
                        //点击 范围在 此 anno 的 view内
                        self.selecetAnno(annotation)
                        break
                    }
                }
            }
        }
    
    func selecetAnno(_ anno: XXXAnotation) {
            
            if aMapView.selectedAnnotations.count == 1 {
                let selectedAnno = aMapView.selectedAnnotations[0]
                if selectedAnno is XXXAnotation {
                    self.aMapView.deselectAnnotation(selectedAnno as! XXXAnotation, animated: true)
                }
            }
            //等待zoomQueue()结束后0.3s
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
                self.aMapView.selectAnnotation(anno, animated: false)
            }
        }
    

    经过处理,即使点击一个已选中的annoView黄色区域,其下方的annoView仍然可以被直接点击

    相关文章

      网友评论

          本文标题:ios高德地图 custom annotaionView 用法

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