ios高德地图 custom annotaionView 用法

本文解决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仍然可以被直接点击

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342