版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2020.06.20 星期六 |
前言
MapKit框架直接從您的應(yīng)用界面顯示地圖或衛(wèi)星圖像,調(diào)出興趣點(diǎn)墩朦,并確定地圖坐標(biāo)的地標(biāo)信息。接下來(lái)幾篇我們就一起看一下這個(gè)框架筒严。感興趣的看下面幾篇文章擒滑。
1. MapKit框架詳細(xì)解析(一) —— 基本概覽(一)
2. MapKit框架詳細(xì)解析(二) —— 基本使用簡(jiǎn)單示例(一)
3. MapKit框架詳細(xì)解析(三) —— 基本使用簡(jiǎn)單示例(二)
4. MapKit框架詳細(xì)解析(四) —— 一個(gè)疊加視圖相關(guān)的簡(jiǎn)單示例(一)
5. MapKit框架詳細(xì)解析(五) —— 一個(gè)疊加視圖相關(guān)的簡(jiǎn)單示例(二)
6. MapKit框架詳細(xì)解析(六) —— 添加自定義圖塊(一)
7. MapKit框架詳細(xì)解析(七) —— 添加自定義圖塊(二)
8. MapKit框架詳細(xì)解析(八) —— 添加自定義圖塊(三)
9. MapKit框架詳細(xì)解析(九) —— 地圖特定區(qū)域放大和創(chuàng)建自定義地圖annotations(一)
10. MapKit框架詳細(xì)解析(十) —— 地圖特定區(qū)域放大和創(chuàng)建自定義地圖annotations(二)
11. MapKit框架詳細(xì)解析(十一) —— 自定義MapKit Tiles(一)
12. MapKit框架詳細(xì)解析(十二) —— 自定義MapKit Tiles(二)
開(kāi)始
首先看下主要內(nèi)容:
在本
MapKit Overlay
教程中,您將學(xué)習(xí)如何在原生iOS
地圖上繪制圖像和線(xiàn)條称勋,以使其對(duì)用戶(hù)更具交互性胸哥。本文內(nèi)容來(lái)自翻譯涯竟。
下面看一下寫(xiě)作環(huán)境:
Swift 5, iOS 13, Xcode 11
下面就是正文了赡鲜。
雖然MapKit
可以輕松地將地圖添加到您的應(yīng)用程序中,但是僅靠這一點(diǎn)并不是很吸引人庐船。 幸運(yùn)的是银酬,您可以使用自定義疊加視圖(custom overlay views)
來(lái)制作更具吸引力的地圖。
在此MapKit
教程中筐钟,您將創(chuàng)建一個(gè)展示Six Flags Magic Mountain的應(yīng)用揩瞪。 完成后,您將獲得一個(gè)交互式的公園地圖篓冲,其中顯示了景點(diǎn)李破,乘車(chē)路線(xiàn)和角色位置。 這個(gè)程序適合所有您在那里快速尋求刺激的人壹将。
在Xcode中打開(kāi)入門(mén)項(xiàng)目嗤攻。
入門(mén)項(xiàng)目包括您將要使用的地圖以及用于打開(kāi)和關(guān)閉不同類(lèi)型疊加層(overlays)
的按鈕。
Build
并運(yùn)行诽俯。 您會(huì)看到以下內(nèi)容:
All About Overlay Views
在開(kāi)始創(chuàng)建疊加視圖(overlay views)
之前妇菱,您需要了解兩個(gè)關(guān)鍵類(lèi):MKOverlay
和MKOverlayRenderer
。
MKOverlay
告訴MapKit
您希望它在何處繪制疊加層暴区。使用此類(lèi)的三個(gè)步驟:
- 1) 首先闯团,創(chuàng)建實(shí)現(xiàn)
MKOverlay
協(xié)議protocol的自定義類(lèi),該類(lèi)具有兩個(gè)必需的屬性:coordinate
和boundingMapRect
仙粱。這些屬性定義了疊加層在地圖上的位置及其大小房交。 - 2) 然后,為要顯示疊加層的每個(gè)區(qū)域創(chuàng)建類(lèi)的實(shí)例伐割。例如候味,在此應(yīng)用中淹遵,您將為過(guò)山車(chē)疊加層創(chuàng)建一個(gè)實(shí)例,為餐廳疊加層創(chuàng)建一個(gè)實(shí)例负溪。
- 3) 最后透揣,將疊加層添加到地圖視圖中。
此時(shí)川抡,地圖知道應(yīng)該在哪里顯示疊加層辐真。但是它不知道在每個(gè)區(qū)域顯示什么。
這就是MKOverlayRenderer
的作用崖堤。對(duì)其進(jìn)行子類(lèi)化可以設(shè)置要在每個(gè)位置顯示的內(nèi)容侍咱。
例如,在此應(yīng)用中密幔,您將繪制過(guò)山車(chē)或餐廳的圖像楔脯。 MapKit
期望提供一個(gè)MKMapView
對(duì)象胯甩,并且此類(lèi)定義地圖視圖使用的繪圖基礎(chǔ)結(jié)構(gòu)昧廷。
看一下入門(mén)項(xiàng)目。在ContentView.swift
中偎箫,您將看到一個(gè)代理方法木柬,該方法可讓您返回疊加視圖(overlay view)
:
func mapView(
_ mapView: MKMapView,
rendererFor overlay: MKOverlay
) -> MKOverlayRenderer
當(dāng)MapKit
意識(shí)到在地圖視圖顯示的區(qū)域中存在MKOverlay
對(duì)象時(shí),MapKit
會(huì)調(diào)用此方法淹办。
綜上所述眉枕,您無(wú)需將MKOverlayRenderer
對(duì)象直接添加到地圖視圖中。 取而代之的是怜森,您告訴地圖有關(guān)要顯示的MKOverlay
對(duì)象的信息速挑,并在委托方法請(qǐng)求它們時(shí)返回MKOverlayRenderers
。
現(xiàn)在副硅,您已經(jīng)了解了理論姥宝,是時(shí)候使用這些概念了!
Adding Your Information to the Map
目前想许,該地圖無(wú)法提供有關(guān)公園的足夠信息伶授。 您的任務(wù)是創(chuàng)建一個(gè)代表整個(gè)公園的疊加層的對(duì)象。
首先流纹,選擇Overlays
組糜烹,然后創(chuàng)建一個(gè)名為ParkMapOverlay.swift
的新Swift
文件。 然后將其內(nèi)容替換為:
import MapKit
class ParkMapOverlay: NSObject, MKOverlay {
let coordinate: CLLocationCoordinate2D
let boundingMapRect: MKMapRect
init(park: Park) {
boundingMapRect = park.overlayBoundingMapRect
coordinate = park.midCoordinate
}
}
符合MKOverlay
會(huì)強(qiáng)制您從NSObject
繼承漱凝。 初始化程序從傳遞的Park
對(duì)象(已在入門(mén)項(xiàng)目中)獲取屬性疮蹦,并將其設(shè)置為相應(yīng)的MKOverlay
屬性。
接下來(lái)茸炒,您需要?jiǎng)?chuàng)建一個(gè)MKOverlayRenderer
愕乎,它知道如何繪制此疊加層阵苇。
在Overlays
組中創(chuàng)建一個(gè)名為ParkMapOverlayView.swift
的新Swift文件。 將其內(nèi)容替換為:
import MapKit
class ParkMapOverlayView: MKOverlayRenderer {
let overlayImage: UIImage
// 1
init(overlay: MKOverlay, overlayImage: UIImage) {
self.overlayImage = overlayImage
super.init(overlay: overlay)
}
// 2
override func draw(
_ mapRect: MKMapRect,
zoomScale: MKZoomScale,
in context: CGContext
) {
guard let imageReference = overlayImage.cgImage else { return }
let rect = self.rect(for: overlay.boundingMapRect)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: 0.0, y: -rect.size.height)
context.draw(imageReference, in: rect)
}
}
以下是您添加的內(nèi)容的細(xì)分:
- 1)
init(overlay:overlayImage :)
通過(guò)提供第二個(gè)參數(shù)來(lái)覆蓋基本方法init(overlay :)
感论。 - 2)
draw(_:zoomScale:in :)
是此類(lèi)的真實(shí)內(nèi)容绅项。 它定義了MapKit
在給定特定MKMapRect
,MKZoomScale
和圖形上下文的CGContext
時(shí)應(yīng)如何呈現(xiàn)此視圖比肄,目的是以適當(dāng)?shù)谋壤龑⒏采w圖像(overlay image)
繪制到上下文上快耿。
注意:
Core Graphics
繪圖的詳細(xì)信息不在本教程的討論范圍之內(nèi)。 但是芳绩,您可以看到上面的代碼使用傳遞的MKMapRect
來(lái)獲取一個(gè)CGRect
掀亥,以便在其中提供在所提供的上下文中繪制圖像。
很好妥色,現(xiàn)在您已經(jīng)有了MKOverlay
和MKOverlayRenderer
搪花,將它們添加到地圖視圖中。
Creating Your First Map Overlay
在ContentView.swift
中嘹害,找到addOverlay()
并將其TODO
內(nèi)容更改為:
let overlay = ParkMapOverlay(park: park)
mapView.addOverlay(overlay)
此方法將ParkMapOverlay
添加到地圖視圖(map view)
撮竿。
看一下updateMapOverlayViews()
。 您會(huì)看到吼拥,當(dāng)用戶(hù)點(diǎn)擊導(dǎo)航欄中的按鈕以顯示地圖疊加層時(shí)倚聚,就會(huì)調(diào)用addOverlay()
。 現(xiàn)在凿可,您已經(jīng)添加了必要的代碼,隨即顯示疊加層授账。
請(qǐng)注意枯跑,updateMapOverlayViews()
還刪除了可能存在的所有注釋和疊加層(annotations and overlays)
,因此您不會(huì)得到重復(fù)的渲染白热。 這不一定有效敛助,但這是一種從地圖上清除先前項(xiàng)目的簡(jiǎn)單方法。
站在您與您在地圖上看到新實(shí)現(xiàn)的疊加層之間的最后一步是前面提到的mapView(_:rendererFor :)
屋确。 將其當(dāng)前的TODO
實(shí)施替換為:
if overlay is ParkMapOverlay {
return ParkMapOverlayView(
overlay: overlay,
overlayImage: UIImage(imageLiteralResourceName: "overlay_park"))
}
當(dāng)MapKit
確定MKOverlay
在視圖中時(shí)纳击,它將調(diào)用此委托方法以獲得渲染器。
在這里攻臀,您可以檢查疊加層是否為ParkMapOverlay
類(lèi)類(lèi)型焕数。 如果是這樣,則加載疊加圖像刨啸,使用疊加圖像創(chuàng)建一個(gè)ParkMapOverlayView實(shí)例堡赔,然后將此實(shí)例返回給調(diào)用者。
不過(guò)设联,這里缺少一小塊:可疑的overlay_park
小圖像是從哪里來(lái)的善已? 這是將地圖與定義的公園邊界疊加在一起的PNG
灼捂。 在Assets.xcassets
中找到的overlay_park
圖像如下所示:
構(gòu)建并運(yùn)行,啟用屏幕頂部的:Overlay:
選項(xiàng)换团,然后加油悉稠! 這是在地圖頂部繪制的公園疊加層:
放大,縮小并四處移動(dòng)艘包。 覆蓋層會(huì)按預(yù)期縮放和移動(dòng)偎球。Cool!
Adding Annotations
如果您曾經(jīng)在原生Maps
應(yīng)用中搜索過(guò)某個(gè)位置辑甜,那么您會(huì)看到這些彩色圖釘(pins)
出現(xiàn)在地圖上衰絮。 這些是使用MKAnnotationView
創(chuàng)建的注釋(annotations)
。 您可以在自己的應(yīng)用程序中使用注釋?zhuān)⑹褂盟璧娜魏螆D像磷醋,而不僅僅是
pins`猫牡!
Annotations
有助于突出顯示公園游客的特定興趣點(diǎn)。 它們的工作方式類(lèi)似于MKOverlay
和MKOverlayRenderer
邓线,但是您將使用MKAnnotation
和MKAnnotationView
淌友。
1. Writing Your First Annotation
首先,在Annotations
組中創(chuàng)建一個(gè)名為AttractionAnnotation.swift
的新Swift
文件骇陈。 然后震庭,將其內(nèi)容替換為:
import MapKit
// 1
enum AttractionType: Int {
case misc = 0
case ride
case food
case firstAid
func image() -> UIImage {
switch self {
case .misc:
return UIImage(imageLiteralResourceName: "star")
case .ride:
return UIImage(imageLiteralResourceName: "ride")
case .food:
return UIImage(imageLiteralResourceName: "food")
case .firstAid:
return UIImage(imageLiteralResourceName: "firstaid")
}
}
}
// 2
class AttractionAnnotation: NSObject, MKAnnotation {
// 3
let coordinate: CLLocationCoordinate2D
let title: String?
let subtitle: String?
let type: AttractionType
// 4
init(
coordinate: CLLocationCoordinate2D,
title: String,
subtitle: String,
type: AttractionType
) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.type = type
}
}
這是您添加的內(nèi)容:
- 1)
AttractionType
可幫助您將每個(gè)景點(diǎn)分類(lèi)為一種類(lèi)型。 該枚舉列出了四種類(lèi)型的注釋?zhuān)弘s項(xiàng)你雌,乘車(chē)器联,食物和急救(misc, rides, foods and first aid)
。 還有一種方便的方法來(lái)獲取正確的annotation
圖像婿崭。 - 2) 您創(chuàng)建此類(lèi)并使其符合 MKAnnotation拨拓。
- 3) 與
MKOverlay
非常相似,MKAnnotation
具有必需的coordinate
屬性氓栈。 您定義了一些特定于此實(shí)現(xiàn)的屬性渣磷。 - 4) 最后,定義一個(gè)初始化程序授瘦,該初始化程序可讓您為每個(gè)屬性分配值醋界。
接下來(lái),您將創(chuàng)建一個(gè)MKAnnotationView
的特定實(shí)例以用于您的annotations
提完。
2. Associating a View With Your Annotation
首先形纺,在Annotations
組中創(chuàng)建另一個(gè)名為AttractionAnnotationView.swift
的Swift
文件。 然后氯葬,將其內(nèi)容替換為以下代碼段:
import MapKit
class AttractionAnnotationView: MKAnnotationView {
// 1
// Required for MKAnnotationView
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// 2
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
guard
let attractionAnnotation = self.annotation as? AttractionAnnotation else {
return
}
image = attractionAnnotation.type.image()
}
}
以下是代碼細(xì)分:
- 1)
MKAnnotationView
需要使用init(coder :)
挡篓。 如果沒(méi)有定義,錯(cuò)誤將阻止您構(gòu)建和運(yùn)行應(yīng)用程序。 為了避免這種情況官研,請(qǐng)定義它并調(diào)用其超類(lèi)初始化程序秽澳。 - 2) 您還可以覆蓋
init(annotation:reuseIdentifier :)
并根據(jù)annotation
的type
屬性設(shè)置其他注釋(annotation
)圖像。
創(chuàng)建annotation
及其相關(guān)視圖之后戏羽,就可以開(kāi)始向地圖視圖添加annotation
了担神!
Adding Annotations to the Map
要確定每個(gè)annotation
的位置,請(qǐng)使用MagicMountainAttractions.plist
文件中的信息始花,該文件位于Park Information
組下妄讯。plist
文件包含有關(guān)公園景點(diǎn)的坐標(biāo)信息和其他詳細(xì)信息。
返回ContentView.swift
并將TODO:
中addAttractionPins()
的實(shí)現(xiàn)替換為:
// 1
guard let attractions = Park.plist("MagicMountainAttractions")
as? [[String: String]] else { return }
// 2
for attraction in attractions {
let coordinate = Park.parseCoord(dict: attraction, fieldName: "location")
let title = attraction["name"] ?? ""
let typeRawValue = Int(attraction["type"] ?? "0") ?? 0
let type = AttractionType(rawValue: typeRawValue) ?? .misc
let subtitle = attraction["subtitle"] ?? ""
// 3
let annotation = AttractionAnnotation(
coordinate: coordinate,
title: title,
subtitle: subtitle,
type: type)
mapView.addAnnotation(annotation)
}
以下是分步細(xì)分:
- 1) 首先酷宵,您閱讀
MagicMountainAttractions.plist
并將其存儲(chǔ)為字典數(shù)組亥贸。 - 2) 然后,您遍歷數(shù)組中的每個(gè)字典浇垦。
- 3) 對(duì)于每個(gè)條目炕置,您都將創(chuàng)建一個(gè)
AttractionAnnotation
實(shí)例以及該點(diǎn)的信息,并將其添加到地圖視圖中男韧。
最后但并非最不重要的一點(diǎn)是朴摊,您需要實(shí)現(xiàn)另一個(gè)委托方法,該方法將MKAnnotationView
實(shí)例提供給地圖視圖此虑,以便它可以自行渲染它們甚纲。
將以下方法添加到文件頂部的Coordinator
類(lèi)中:
func mapView(
_ mapView: MKMapView,
viewFor annotation: MKAnnotation
) -> MKAnnotationView? {
let annotationView = AttractionAnnotationView(
annotation: annotation,
reuseIdentifier: "Attraction")
annotationView.canShowCallout = true
return annotationView
}
此方法接收選定的MKAnnotation
并使用它來(lái)創(chuàng)建AttractionAnnotationView
。 由于canShowCallout
屬性設(shè)置為true
朦前,因此當(dāng)用戶(hù)觸摸注釋(annotation)
時(shí)會(huì)出現(xiàn)一個(gè)標(biāo)注(call-out)
介杆。 最后,該方法返回注釋視圖(annotation view)
况既。
Build
并運(yùn)行以查看實(shí)際中的annotations
这溅! 不要忘記打開(kāi):Pins:
選項(xiàng)。
在這一點(diǎn)上棒仍,Attraction pins
看起來(lái)相當(dāng)鋒利!
到目前為止臭胜,您已經(jīng)介紹了MapKit
的一些復(fù)雜部分莫其,包括疊加層和注釋(overlays and annotations)
。 但是耸三,如果您需要使用一些繪圖圖元(如直線(xiàn)和圓)怎么辦乱陡?
MapKit
框架還允許您直接繪制到地圖視圖上。 MapKit
為此提供了MKPolyline
仪壮,MKPolygon
和MKCircle
憨颠。 是時(shí)候嘗試一下了!
I Walk The Line: MKPolyline
如果您去過(guò)魔術(shù)山(Magic Mountain)
,您就會(huì)知道歌利亞(Goliath)
過(guò)山車(chē)是一次不可思議的旅程爽彤。 一些車(chē)手喜歡在走入大門(mén)時(shí)就做出一條直線(xiàn)养盗!
為了幫助這些騎手,您將畫(huà)一條從公園入口到巨人的路徑适篙。
MKPolyline
是繪制連接多個(gè)點(diǎn)的路徑的絕佳解決方案往核,例如繪制從點(diǎn)A到點(diǎn)B的非線(xiàn)性路線(xiàn)。
要繪制折線(xiàn)(polyline)
嚷节,您需要按照繪制順序繪制一系列經(jīng)度和緯度坐標(biāo)聂儒。 再次在Park Information
文件夾中找到的EntranceToGoliathRoute.plist
包含路徑信息。
現(xiàn)在硫痰,您需要一種方法來(lái)讀取該plist
文件并創(chuàng)建供騎手遵循的路線(xiàn)衩婚。
首先,打開(kāi)ContentView.swift
并找到addRoute()
效斑。 然后非春,將其當(dāng)前的TODO
實(shí)施替換為:
guard let points = Park.plist("EntranceToGoliathRoute") as? [String] else {
return
}
let cgPoints = points.map { NSCoder.cgPoint(for: $0) }
let coords = cgPoints.map { CLLocationCoordinate2D(
latitude: CLLocationDegrees($0.x),
longitude: CLLocationDegrees($0.y))
}
let myPolyline = MKPolyline(coordinates: coords, count: coords.count)
mapView.addOverlay(myPolyline)
此方法讀取EntranceToGoliathRoute.plist
并將單個(gè)坐標(biāo)字符串轉(zhuǎn)換為CLLocationCoordinate2D
結(jié)構(gòu)。
實(shí)現(xiàn)折線(xiàn)非常簡(jiǎn)單:您只需創(chuàng)建一個(gè)包含所有點(diǎn)的數(shù)組鳍悠,然后將其傳遞給MKPolyline
税娜! 沒(méi)有比這容易的多了。
請(qǐng)記住藏研,每當(dāng)用戶(hù)通過(guò)UI
切換此選項(xiàng)時(shí)敬矩,updateMapOverlayViews()
已經(jīng)調(diào)用addRoute()
。 現(xiàn)在剩下的就是讓您更新委托方法蠢挡,以便它返回要在地圖視圖上呈現(xiàn)的實(shí)際視圖弧岳。
返回mapView(_:rendererFor :)
并將此else if
子句添加到現(xiàn)有條件中:
else if overlay is MKPolyline {
let lineView = MKPolylineRenderer(overlay: overlay)
lineView.strokeColor = .green
return lineView
}
顯示折線(xiàn)視圖的過(guò)程與以前的疊加視圖非常相似。 但是业踏,在這種情況下禽炬,您無(wú)需創(chuàng)建任何自定義視圖對(duì)象。 您只需使用提供的MKPolyLineRenderer
類(lèi)并使用疊加層(overlay)
初始化一個(gè)新實(shí)例勤家。
MKPolyLineRenderer
還可讓您更改某些折線(xiàn)的屬性腹尖。 在這種情況下,您已經(jīng)修改了筆觸顏色以顯示為綠色伐脖。
Build
并運(yùn)行您的應(yīng)用程序热幔。 啟用:Route:
選項(xiàng),它會(huì)顯示在屏幕上:
現(xiàn)在讼庇,Goliath fanatics
可以在創(chuàng)紀(jì)錄的時(shí)間內(nèi)登上過(guò)山車(chē)绎巨!
最好向公園顧客顯示公園邊界,因?yàn)楣珗@實(shí)際上并沒(méi)有占據(jù)屏幕上顯示的整個(gè)空間蠕啄。
您可以使用MKPolyline
在公園邊界周?chē)L制形狀场勤,但是MapKit
提供了另一個(gè)專(zhuān)門(mén)設(shè)計(jì)用于繪制閉合多邊形的類(lèi):MKPolygon
。
Don’t Fence Me In: MKPolygon
MKPolygon
與MKPolyline
相似,不同之處在于坐標(biāo)集中的第一個(gè)點(diǎn)和最后一個(gè)點(diǎn)相互連接以創(chuàng)建閉合形狀和媳。
您將創(chuàng)建一個(gè)MKPolygon
作為顯示公園邊界的疊加層格遭。 公園邊界坐標(biāo)在MagicMountain.plist
中定義。 查看Park.swift
中的init(filename :)
以查看從plist
文件讀取邊界點(diǎn)的位置窗价。
現(xiàn)在如庭,在ContentView.swift
中,將addBoundary()
的TODO
實(shí)現(xiàn)替換為:
mapView.addOverlay(MKPolygon(
coordinates: park.boundary,
count: park.boundary.count))
給定公園實(shí)例的邊界數(shù)組和點(diǎn)數(shù)撼港,您可以快速輕松地創(chuàng)建一個(gè)新的MKPolygon
實(shí)例坪它!
你能猜到下一步嗎? 與您對(duì)MKPolyline
所做的類(lèi)似帝牡。
是的往毡,沒(méi)錯(cuò)。 MKPolygon
像MKPolyline
一樣符合MKOverlay
靶溜,因此您需要再次更新委托方法开瞭。
返回mapView(_:rendererFor :)
并將此else if
子句添加到現(xiàn)有條件中:
else if overlay is MKPolygon {
let polygonView = MKPolygonRenderer(overlay: overlay)
polygonView.strokeColor = .magenta
return polygonView
}
您創(chuàng)建一個(gè)MKOverlayView
作為MKPolygonRenderer
的實(shí)例,并將stroke
顏色設(shè)置為洋紅色罩息。
運(yùn)行應(yīng)用程序并啟用:Bound:
選項(xiàng)嗤详,以查看新邊界的實(shí)際作用。 您可能需要縮小以使公園邊界適合模擬器的屏幕邊界瓷炮。
這會(huì)考慮到折線(xiàn)和多邊形(polylines and polygons)
葱色。 涉及到的最后一種繪制方法是繪制圓圈作為疊加層,您將使用MKCircle
進(jìn)行繪制娘香。
Circle in the Sand: MKCircle
MKCircle
也非常類(lèi)似于MKPolyline
和MKPolygon
苍狰,不同之處在于,在給定中心坐標(biāo)點(diǎn)和確定圓弧大小的半徑時(shí)烘绽,它會(huì)繪制一個(gè)圓淋昭。
許多公園游客喜歡與人物一起參觀。 您可以通過(guò)用圓圈標(biāo)記最后在地圖上發(fā)現(xiàn)characters
的位置來(lái)幫助他們找到字符安接。 MKCircle
疊加層使您可以輕松地執(zhí)行此操作翔忽。
Park Information
文件夾還包含角色位置文件。 每個(gè)文件都是由幾個(gè)坐標(biāo)組成的數(shù)組盏檐,用戶(hù)可以在其中發(fā)現(xiàn)角色呀打。
首先,在Models
組下創(chuàng)建一個(gè)名為Character.swift
的新swift
文件糯笙。 然后,將其內(nèi)容替換為以下代碼:
import MapKit
// 1
class Character: MKCircle {
// 2
private var name: String?
var color: UIColor?
// 3
convenience init(filename: String, color: UIColor) {
guard let points = Park.plist(filename) as? [String] else {
self.init()
return
}
let cgPoints = points.map { NSCoder.cgPoint(for: $0) }
let coords = cgPoints.map {
CLLocationCoordinate2D(
latitude: CLLocationDegrees($0.x),
longitude: CLLocationDegrees($0.y))
}
let randomCenter = coords[Int.random(in: 0...3)]
let randomRadius = CLLocationDistance(Int.random(in: 5...39))
self.init(center: randomCenter, radius: randomRadius)
self.name = filename
self.color = color
}
}
此代碼的作用如下:
- 1)
Character
類(lèi)符合MKCircle
協(xié)議撩银。 - 2) 它定義了兩個(gè)可選屬性:
name
和color
给涕。 - 3) 便捷初始化程序接受
plist
文件名和顏色來(lái)繪制圓圈。 然后,它從plist
文件中讀取數(shù)據(jù)够庙,并從文件的四個(gè)位置中選擇一個(gè)隨機(jī)位置恭应。 接下來(lái),它選擇一個(gè)隨機(jī)半徑來(lái)模擬時(shí)間變化耘眨。 返回的MKCircle
已設(shè)置好昼榛,可以放到地圖上了!
現(xiàn)在剔难,您需要一種添加characters
的方法胆屿。 因此,打開(kāi)ContentView.swift
并將addCharacterLocation()
的TODO
實(shí)現(xiàn)替換為:
mapView.addOverlay(Character(filename: "BatmanLocations", color: .blue))
mapView.addOverlay(Character(filename: "TazLocations", color: .orange))
mapView.addOverlay(Character(filename: "TweetyBirdLocations", color: .yellow))
該方法對(duì)每個(gè)character
執(zhí)行幾乎相同的操作:它為每個(gè)字符傳遞plist
文件名偶宫,確定顏色并將其作為覆蓋添加到地圖上非迹。
你幾乎完成! 你還記得最后一步嗎纯趋?
對(duì)憎兽! 您需要使用委托方法為地圖視圖提供MKOverlayView
。
返回mapView(_:rendererFor :)
并將此else if
子句添加到現(xiàn)有條件中:
else if let character = overlay as? Character {
let circleView = MKCircleRenderer(overlay: character)
circleView.strokeColor = character.color
return circleView
}
Build
并運(yùn)行該應(yīng)用程序吵冒,然后啟用:Characters:
選項(xiàng)以查看每個(gè)人都隱藏在哪里纯命!
有許多更高級(jí),甚至更有效的方法來(lái)創(chuàng)建overlays
痹栖。 例如亿汞,您可以使用KML tiles
或其他第三方提供的資源。
后記
本篇主要講述了
Overlay Views
结耀,感興趣的給個(gè)贊或者關(guān)注~~~