基于 Swift 多地圖源業(yè)務(wù)向地圖控件實(shí)現(xiàn)(一):封裝地圖源

上一篇談了整體的設(shè)計(jì)思路执虹,這篇談一下具體的實(shí)現(xiàn)設(shè)計(jì)拓挥。因?yàn)槲业捻?xiàng)目里第一個(gè)接入的地圖源是高德地圖,這里的接口以高德地圖作為示范袋励。

既然要接入多個(gè)地圖源侥啤,可以良好的支持地圖源切換,那么第一步就是隔離具體地圖源茬故。隔離具體實(shí)現(xiàn)最常使用的方式就是使用接口隔離愿棋。UITableView 中常用的 UITableViewDataSource 也是類似的機(jī)制,使用接口隔離了具體的 dataSource 實(shí)現(xiàn)均牢。

我們定義一個(gè) protocol 來(lái)聲明地圖源應(yīng)該提供的能力:

public protocol VendorMapView: class {
    /// 實(shí)際坐標(biāo)轉(zhuǎn)換到指定 View 上坐標(biāo)
    func convert(coordinate: CLLocationCoordinate2D, toPointTo view: UIView?) -> CGPoint
    
    /// 轉(zhuǎn)換 View 上的點(diǎn)為實(shí)際坐標(biāo)
    func convert(point: CGPoint, toCoordinateFrom view: UIView?) -> CLLocationCoordinate2D
    
    func setCenter(coordinate: CLLocationCoordinate2D)    
}

我簡(jiǎn)化了代碼,這里只聲明了核心的坐標(biāo)轉(zhuǎn)換方法和作為演示的設(shè)置地圖中心坐標(biāo)的方法才睹。聲明實(shí)現(xiàn)的對(duì)象需要是類是因?yàn)槲覀兠鞔_的知道實(shí)現(xiàn)這個(gè)接口的對(duì)象是具體的地圖源徘跪,是 UIView 類型。

下一步要做的是讓地圖源實(shí)現(xiàn)這個(gè)接口琅攘。

import MAMapKit

extension MAMapView: VendorMapView {

    public func convert(coordinate: CLLocationCoordinate2D, toPointTo view: UIView?) -> CGPoint {
        return convert(coordinate, toPointTo: view)
    }
    
    public func convert(point: CGPoint, toCoordinateFrom view: UIView?) -> CLLocationCoordinate2D {
        return convert(point, toCoordinateFrom: view)
    }

    public func setCenter(coordinate: CLLocationCoordinate2D) {
        setCenter(coordinate, animated: true)
    }

}

到這里我們已經(jīng)隔離了具體的地圖源了垮庐。假設(shè)我們自定義地圖名為 MeshMapView,現(xiàn)在在我們自定義地圖中聲明地圖代理:

public class MeshMapView: UIView {
    
    public static var currentMapVendor = MapVendor.gaode
    
    var gaodeMap: MAMapView?
    var baiduMap: BMKMapView?

    var map: VendorMapView? {
        switch MeshMapView.currentMapVendor {
        case .gaode:
            return gaodeMap
        case .baidu:
            return baiduMap
        }
    }
}

extension MeshMapView {
    
    /// 地圖提供商
    public enum MapVendor: CaseIterable {
        case gaode, baidu
        
        var descrption: String {
            switch self {
            case .gaode:
                return "高德"
            case .baidu:
                return "百度"
            }
        }
    }
}

因?yàn)榈貓D控件是針對(duì)業(yè)務(wù)封裝的坞琴,可能有很多業(yè)務(wù)相關(guān)的枚舉類型哨查,因此在單獨(dú)的 extension 中聲明地圖控件的相關(guān)枚舉。我們需要知道當(dāng)前的地圖源是哪一個(gè)供應(yīng)商剧辐,因此使用 MapVendor 列出所有的地圖供應(yīng)商寒亥。

在我的業(yè)務(wù)場(chǎng)景里,如果在某個(gè)頁(yè)面選擇了某個(gè)地圖源荧关,那么之后所有的地圖控件都使用這個(gè)地圖源溉奕。從這個(gè)需求出發(fā),因此當(dāng)前選擇的地圖源是一個(gè)全局的設(shè)置忍啤,因此聲明為靜態(tài)屬性加勤。
具體地圖源的選擇分發(fā)我們用 VendorMapView 類型的 map 進(jìn)行隔離。

接著補(bǔ)充一下控件的初始化方法:

import SnapKit

public class MeshMapView: UIView {

    public init() {
        super.init(frame: CGRect.zero)
        addVendorMapView()
    }

    private func addVendorMapView() {
        switch MeshMapView.currentMapVendor {
        case .gaode:
            let gaodeMap = MAMapView(frame: CGRect.zero)
            gaodeMap.mapType = .satellite
            gaodeMap.zoomLevel = 16.5
            addSubview(gaodeMap)
            gaodeMap.snp.makeConstraints { (make) in
                make.edges.equalToSuperview()
            }
            self.gaodeMap = gaodeMap
        case .baidu:
           // 。鳄梅。叠国。
        }
    }
}

到這里的代碼實(shí)現(xiàn)了通過(guò) currentMapVendor 屬性可以配置地圖控件的地圖源。如果要增加一個(gè)地圖源戴尸,只需要讓新地圖源實(shí)現(xiàn) VendorMapView粟焊,MapVendor 枚舉增加一個(gè)類型,最后在地圖控件中增加實(shí)例的初始化方法校赤。這個(gè)設(shè)計(jì)對(duì)地圖源的新增開(kāi)放吆玖,不需要修改原有的代碼邏輯,通過(guò)新增加代碼就可以實(shí)現(xiàn)马篮,容易維護(hù)沾乘。
不過(guò)上面的 addVendorMapView 方法還有優(yōu)化的空間。每個(gè)地圖的初始化配置的邏輯是具體實(shí)現(xiàn)浑测,嚴(yán)格的說(shuō)和 MeshMapView 并不直接相關(guān)翅阵,MeshMapView 不關(guān)心具體地圖供應(yīng)商的配置。因此可以把地圖源初始化配置代碼移到地圖源自身擴(kuò)展中:

public protocol VendorMapView: class {
    func initialConfig()
}

extension MAMapView: VendorMapView {
    func initialConfig() {
        mapType = .satellite
        zoomLevel = 16.5
    }
}

但是初始化配置的代碼寫在一個(gè)地方也是可以接受的迁央。好處是如果一個(gè)通用的配置掷匠,比如地圖的默認(rèn) zoomLevel 要改為 10,如果初始化代碼寫在一起只在一個(gè)地方改就可以了岖圈,不用去四處找讹语。這里我的想法是雖然幾個(gè)地圖源初始化配置寫在一起方法的長(zhǎng)度可能會(huì)有三四十行,但是初始化代碼邏輯復(fù)雜度很低蜂科,寫在一個(gè)方法里也是可以接受的顽决。看開(kāi)發(fā)者個(gè)人喜好了导匣。

最后一步我們要暴露自定義地圖控件的地圖相關(guān)方法才菠。因?yàn)檫@類方法只是封裝了一層,最后是直接調(diào)用到具體地圖源贡定,不是業(yè)務(wù)相關(guān)的赋访,因此建議單獨(dú)寫在一個(gè) extension 里:

extension MeshMapView {
    
    public func setCenter(coordinate: CLLocationCoordinate2D) {
        map?.setCenter(coordinate: standardCoordinate)
    }
}

到這里我們就完成地圖源的隔離與封裝。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缓待,一起剝皮案震驚了整個(gè)濱河市蚓耽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌命斧,老刑警劉巖田晚,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異国葬,居然都是意外死亡贤徒,警方通過(guò)查閱死者的電腦和手機(jī)芹壕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)接奈,“玉大人踢涌,你說(shuō)我怎么就攤上這事⌒蚧拢” “怎么了睁壁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)互捌。 經(jīng)常有香客問(wèn)我潘明,道長(zhǎng),這世上最難降的妖魔是什么秕噪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任钳降,我火速辦了婚禮,結(jié)果婚禮上腌巾,老公的妹妹穿的比我還像新娘遂填。我一直安慰自己,他們只是感情好澈蝙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布吓坚。 她就那樣靜靜地躺著,像睡著了一般灯荧。 火紅的嫁衣襯著肌膚如雪礁击。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天逗载,我揣著相機(jī)與錄音客税,去河邊找鬼。 笑死撕贞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的测垛。 我是一名探鬼主播捏膨,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼食侮!你這毒婦竟也來(lái)了号涯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锯七,失蹤者是張志新(化名)和其女友劉穎链快,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體眉尸,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡域蜗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年巨双,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霉祸。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筑累,死狀恐怖睦霎,靈堂內(nèi)的尸體忽然破棺而出筏勒,到底是詐尸還是另有隱情捎拯,我是刑警寧澤静尼,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布恤批,位于F島的核電站独柑,受9級(jí)特大地震影響茵乱,放射性物質(zhì)發(fā)生泄漏桨吊。R本人自食惡果不足惜贱田,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一缅茉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧湘换,春花似錦宾舅、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至帆离,卻和暖如春蔬蕊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哥谷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工岸夯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人们妥。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓猜扮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親监婶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旅赢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容