iOS 高德SDK應用實踐(三)—— 自定義氣泡CalloutView

級別:★☆☆☆☆
標籤:「iOS」「MAMapKit」「高德」
做者: 647
審校: QiShare團隊php


前言:
前段時間,在一個項目中須要自定義地圖。 因而,咱們選擇了接入了高德地圖。
基於此次自定義地圖的實踐,總結一些使用上的一些小細節,並計劃落地一系列地圖相關的文章。
目錄以下:
iOS 高德SDK應用實踐(一)—— 簡介與初始化地圖
iOS 高德SDK應用實踐(二)—— 自定義大頭針AnnotationView
iOS 高德SDK應用實踐(三)—— 自定義氣泡CalloutViewgit


本篇將介紹CalloutView的默認簡單用法,以及如何自定義氣泡CalloutViewgithub

1、什麼是氣泡CalloutView?

CalloutView(氣泡)是高德地圖AnnotationView(大頭針)上的一個控件,它的存在創建在AnnotationView之上,當選擇某個AnnotationView時,就會彈出一個CalloutView(氣泡)。swift

系統默認樣式以下:微信

2、默認CalloutView的簡單使用

若是項目的自定義程度不高,直接初始化系統的calloutView使用便可。ide

<MAMapViewDelegate>中的mapView:viewForAnnotation:回調方法中,把annotationView!.canShowCallout = true,同時能夠配置一些callout屬性。ui

// 改變普通標註的AnnotationView
        if annotation.isKind(of: MAPointAnnotation.self) {
            let pointReuseIndetifier = "pointReuseIndetifier"
            var annotationView: MAPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as! MAPinAnnotationView?
            
            if annotationView == nil {
                annotationView = MAPinAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
            }
            
            annotationView!.canShowCallout = true
            annotationView!.animatesDrop = true
            annotationView!.isDraggable = true
            annotationView!.rightCalloutAccessoryView = UIButton(type: UIButton.ButtonType.detailDisclosure)
            
            return annotationView!
        }
複製代碼

3、如何添加自定義氣泡CalloutView?

  • 第一步:首先,須要在<MAMapViewDelegate>中的mapView:viewForAnnotation:回調方法中,把系統calloutView關閉。
xxxAnnotationView?.canShowCallout = false
複製代碼
  • 第二步:其次,新建一個CustomCalloutView,繼承於UIView。 根據本身的需求,進行自定義UI視圖。
import UIKit

class CustomCalloutView: UIView {

    var leftBtn: UIButton!
    var rightBtn: UIButton!
    
    var leftBtnBlock : ((_:UIButton?)->Void)? // 左邊按鈕的回調
    var rightBtnBlock : ((_:UIButton?)->Void)? // 右邊按鈕的回調
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.backgroundColor = .white
        self.layer.cornerRadius = self.frame.size.height / 2
        self.layer.masksToBounds = true
        
        leftBtn = UIButton(type: .custom)
        leftBtn.frame = CGRect(x: 0, y: 0, width: 45.0, height: 45.0)
        leftBtn.setImage(UIImage(named: "QiShare"), for: .normal)
        leftBtn.addTarget(self, action: #selector(leftBtnClicked(button:)), for: UIControl.Event.touchUpInside)
        self.addSubview(leftBtn)
        
        rightBtn = UIButton(type: .custom)
        rightBtn.frame = CGRect(x: self.frame.size.width - 45.0, y: 0, width: 45.0, height: 45.0)
        rightBtn.setImage(UIImage(named: "QiShare"), for: .normal)
        rightBtn.addTarget(self, action: #selector(rightBtnClicked(button:)), for: UIControl.Event.touchUpInside)
        self.addSubview(rightBtn)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func leftBtnClicked(button: UIButton) {
        print("left button clicked")
        if leftBtnBlock != nil {
            leftBtnBlock!(button)
        }
    }
    
    @objc func rightBtnClicked(button: UIButton) {
        print("right button clicked")
        if rightBtnBlock != nil {
            rightBtnBlock!(button)
        }
    }
}

複製代碼
  • 第三步:重寫CustomAnnotationView裏的setSelected方法。
override func setSelected(_ selected: Bool, animated: Bool) {
        
        if self.isSelected == selected{
            return;
        }
        
        if selected {
            if calloutView == nil {
                calloutView = CustomCalloutView.init(frame: CGRect.init(x: 0, y: 0, width: 100, height: 45))
                calloutView!.center = CGPoint.init(x: bounds.width/2 + calloutOffset.x, y: -calloutView!.bounds.height/2 + calloutOffset.y)
                calloutView?.leftBtnBlock = leftBtnBlock
                calloutView?.rightBtnBlock = rightBtnBlock
            }
            addSubview(calloutView!)
        } else {
            calloutView!.removeFromSuperview()
        }
        super.setSelected(selected, animated: animated)
    }
複製代碼

注意:這時,會發現一個問題。CalloutView雖然能顯示,可是CalloutView上的點擊事件並不會響應。spa

緣由以下:3d

  • CalloutViewsuperViewAnnotationView。 而CalloutViewframeAnnotationViewframe以外。 根據iOS 事件響應鏈的原則:超過父視圖frame的子視圖沒法響應事件, 所以,沒法響應CalloutView上的點擊事件。

解決方案,以下:code

  • 第四步:重寫AnnotationViewhitTest方法。 在AnnotationViewhitTest方法中,添加上CalloutView按鈕的響應區域。 從而,擴大AnnotationView事件響應的範圍。
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        
        var view = super.hitTest(point, with: event)
        
        if view == nil {
            
            if self.calloutView == nil {
                return view
            }
            
            let temPoint1: CGPoint = (self.calloutView?.leftBtn.convert(point, from: self))!
            let temPoint2: CGPoint = (self.calloutView?.rightBtn.convert(point, from: self))!
            
            if (self.calloutView?.leftBtn.bounds.contains(temPoint1))! {
                view = self.calloutView!.leftBtn
            }
            
            if (self.calloutView?.rightBtn.bounds.contains(temPoint2))! {
                view = self.calloutView!.rightBtn
            }
        }
        
        return view
    }
複製代碼

最終,效果如圖:

Demo:源碼

最後,更多詳細信息,請參考:高德地圖官方文檔


瞭解更多iOS及相關新技術,請關注咱們的公衆號:

小編微信:可加並拉入《QiShare技術交流羣》。

關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)

推薦文章:
2019蘋果秋季新品發佈會速覽
申請蘋果開發者帳號的流程
Swift 5.1 (3) - 字符串
用Flutter 寫一個簡單頁面
5分鐘,帶你迅速上手Markdown語法
Swift 5.1 (2) - 運算符
Swift 5.1(1) - 基礎
Sign In With Apple(一)
奇舞週刊

相關文章
相關標籤/搜索