版本记录
版本号 | 时间 |
---|---|
V1.0 | 2020.04.26 星期日 |
前言
MapKit框架直接从您的应用界面显示地图或卫星图像,调出兴趣点,并确定地图坐标的地标信息。接下来几篇我们就一起看一下这个框架。感兴趣的看下面几篇文章。
1. MapKit框架详细解析(一) —— 基本概览(一)
2. MapKit框架详细解析(二) —— 基本使用简单示例(一)
3. MapKit框架详细解析(三) —— 基本使用简单示例(二)
4. MapKit框架详细解析(四) —— 一个叠加视图相关的简单示例(一)
5. MapKit框架详细解析(五) —— 一个叠加视图相关的简单示例(二)
6. MapKit框架详细解析(六) —— 添加自定义图块(一)
7. MapKit框架详细解析(七) —— 添加自定义图块(二)
8. MapKit框架详细解析(八) —— 添加自定义图块(三)
开始
首先看下主要内容:
了解如何使用功能强大的
MapKit
框架来构建交互式地图,显示位置详细信息并启动用于行车路线的地图。文章来自翻译。
下面看下写作环境
Swift 5, iOS 13, Xcode 11
MapKit
是iOS
设备上可用的功能强大的API
,可轻松显示地图,标记位置,增强自定义数据甚至在顶部绘制路线或其他形状。
在此MapKit教程中,您将制作HonoluluArt
,此应用程序可缩放到Honolulu
中的位置并在地图上标记公共艺术品。 您将实现标记的标注详细信息按钮,以启动Maps应用并打开艺术品的行车路线。 然后,您将从Honolulu city
数据门户网站解析GeoJSON
文件,以提取公共艺术品特征并将其标记在地图上。
在此过程中,您将学习如何:
- 将
MapKit
地图添加到您的应用。 - 缩放到特定位置。
- 解析
GeoJSON
数据以创建自定义地图注释。
打开开始项目中的Main.storyboard
,然后从Object library
中将Map Kit View
拖到场景的中间。 将Map View
限制为父视图(而不是“安全区域”),并在所有边缘上将其设置为0,以便将其扩展到带缺口设备的“安全区域”中。
构建并运行。 现在,您可以使用Apple Maps
完全缩放和平移的地图,显示您当前位置的大陆!
到目前为止,很好,是吗?
您想放大特定的区域。 为此,您需要获取编码!
打开ViewController.swift
并在import UIKit
语句下面添加以下内容:
import MapKit
接下来,您需要在ViewController.swift
中的MKMapView
设置outlet
。
在viewDidLoad()
之前添加以下outlet
代码:
@IBOutlet private var mapView: MKMapView!
然后,转到Main.storyboard
并将Map View
链接到新的outlet
:
Setting the Visible Area
回到ViewController
。找到viewDidLoad()
,并在方法末尾添加以下内容:
// Set initial location in Honolulu
let initialLocation = CLLocation(latitude: 21.282778, longitude: -157.829444)
您将使用此设置将地图视图的起始坐标设置为Honolulu
的一个点。
在告诉地图要显示什么内容时,提供纬度和经度就足以使地图居中。但是,您还必须指定要显示的矩形区域,以获得正确的缩放级别。
在ViewController.swift
的末尾添加以下私有扩展:
private extension MKMapView {
func centerToLocation(
_ location: CLLocation,
regionRadius: CLLocationDistance = 1000
) {
let coordinateRegion = MKCoordinateRegion(
center: location.coordinate,
latitudinalMeters: regionRadius,
longitudinalMeters: regionRadius)
setRegion(coordinateRegion, animated: true)
}
}
location
参数是中心点。根据regionRadius
的距离,该区域将具有南北和东西跨度,默认为1000
米,略多于半英里,这对于在GeoJSON
文件中绘制公共艺术品数据非常有用。
setRegion(_:animated:)
告诉MKMapView
显示由MKCoordinateRegion
表示的区域。地图视图会自动将当前视图转换为所需的区域,带有一个整洁的缩放动画,不需要额外的代码!
在viewDidLoad()
中,在方法的末尾添加以下行:
mapView.centerToLocation(initialLocation)
这将调用helper
方法以在启动时放大到initialLocation
。
构建和运行。你会发现自己在Waikiki. Aloha
的中心。
Constraining the Camera
到目前为止,你可以去地图上任何你想去的地方,但我们只对Oahu
兴趣。你还可以在缩放地图到目前为止,岛屿只有几个像素!MapKit
能够约束用户在指定区域内平移和缩放地图。
注意:要放大模拟器,按住
Option
并拖动地图视图。
同样在viewDidLoad()
中,在方法的末尾添加以下行:
let oahuCenter = CLLocation(latitude: 21.4765, longitude: -157.9647)
let region = MKCoordinateRegion(
center: oahuCenter.coordinate,
latitudinalMeters: 50000,
longitudinalMeters: 60000)
mapView.setCameraBoundary(
MKMapView.CameraBoundary(coordinateRegion: region),
animated: true)
let zoomRange = MKMapView.CameraZoomRange(maxCenterCoordinateDistance: 200000)
mapView.setCameraZoomRange(zoomRange, animated: true)
构建和运行。现在当你缩小的时候,你不能让Oahu
像以前一样小。你只能平移地图视图来查看岛的北部、南部、东部和西部的边缘。
MapKit
使用一个内部摄像机来确定地图的视点在哪里,视场的范围有多大,并使视点移动。当您指定一个具有中心和区域矩形的摄像机边界时,摄像机中心始终位于此区域内。
如果用户试图移出该区域,则视图不会进一步滚动。让他们专注于你想让他们看到的地方。6万米宽、5万米高的区域大小很好地限制了Oahu
的地图视野。
MapKit
视图摄像机在缩放时跟踪它与视图中心的距离。设置相机的缩放范围最大中心距离约束限制了视野缩小的距离和Oahu
岛变得多么小。这在向地图添加兴趣点(points of interest)
时更有帮助,这是下一步!
Obtaining Public Art Data
下一步是围绕当前位置绘制有趣的数据。
嗯,这取决于你现在的位置。和许多城市一样,Honolulu
也有一个开放的数据门户 Open Data Portal,以改善公众对政府数据的访问。
Honolulu
数据门户的一个方便特性是能够以GeoJSON
格式导出数据集——一种JSON
格式,用于表示地理空间特性及其元数据。MapKit
最近的一个特性使得在您的应用程序中使用GeoJSON
数据变得超级容易,您很快就会看到这一点。
注意:在您完成本教程之后,查看附近的城市是否有另一个您可以使用的
GeoJSON
格式的数据集。一旦你看到它是多么容易,你可能会发现它有趣的绘图在同一地图上的不同数据集。
在本教程中,您将使用檀香山公共艺术Honolulu Public Art数据集。为了简单起见,我已经从门户导出了这些数据,并将其包含在starter项目中,当然,为了便于阅读,这些数据经过了良好的格式化。这是我最起码能做的。
要了解此数据集中的项,请打开Xcode编辑器中的PublicArt.geojson
。在顶层你会看到:
{
"type": "FeatureCollection",
"features": [ ... ]
}
键features
的值是类型为Feature
的GeoJSON
对象数组。每个对象都包含一些标准键,以及一个properties
字典,其中包含由数据门户创建的一些自定义字段。geometry
键是你找到特征的坐标的地方。
看看第一个:
{
"type":"Feature",
"properties":{
"location":"Lester McCoy Pavilion",
"latitude":"21.290824",
"description":"...",
"thumb":null,
"credit":"Funded by the Works Progress Administration",
"objectid":"1930.01.01",
"creator":"Robert Lee Eskridge",
"longitude":"-157.85131",
"imagefile":"http://....JPG",
"date":"1935",
"discipline":"Mural",
"title":"The Makahiki Festival - The Makai Mural",
"access":"Limited"
},
"geometry":{
"type":"Point",
"coordinates":[-157.85131,21.290824]
}
}
1. GeoJSON Properties
不要太担心GeoJSON
数据格式。您很快就会看到,导入它基本上是自动的!基本部分是属性字典和坐标。
对于本教程,您将只使用几个属性:艺术品的位置名称、规程、标题、纬度和经度:
Location name: Lester McCoy Pavilion.
Discipline: Mural.
Title: The Makahiki Festival – The Makai Mural.
Latitude: 21.290824.
Longitude: -157.85131.
注意:如果你想了解更多关于格式的信息,你可以探索整个世界。官方网站official website是有点稀疏,RFC是高度技术性的,但维基百科Wikipedia article的文章是可读的。
它是一种广泛支持的格式,适用于所有地理空间方面的内容。一些有用的工具包括geojson.io是一个测试和编辑
GeoJSON
数据的有用站点,GitHub将自动在地图上的存储库中呈现任何.geojson
文件。
在本教程的后面,您将使用整个数据集。但首先,为了直接进入MapKit
,您将在地图上绘制一个艺术品。
Showing Artwork on the Map
在PublicArt.geojson
,按下Command-L
,跳到第1354
行。这是威基基公园(Waikiki Gateway Park)
里的大卫王卡拉卡瓦King David Kalakaua
的青铜雕像。
这个项目的属性是:
Location name: Waikiki Gateway Park
Discipline: Sculpture
Title: King David Kalakaua
Latitude: 21.283921
Longitude: -157.831661
要在地图视图中显示这一点,您必须创建一个map annotation
。map annotation
是绑定到特定位置的小块信息。苹果的Maps
应用程序通常将它们表示为小图钉。
要创建注释annotations
,您需要创建一个符合MKAnnotation
的类,将该注释添加到地图中,并告诉地图该如何显示该注释。
1. The Artwork Class
首先,在“项目导航器”中右键单击HonoluluArt
文件夹,选择New File…
,选择Swift File
,并将新文件命名为Artwork.swift
。
在编辑器中打开Artwork.swift
,并添加以下import Foundation
:
import MapKit
class Artwork: NSObject, MKAnnotation {
let title: String?
let locationName: String?
let discipline: String?
let coordinate: CLLocationCoordinate2D
init(
title: String?,
locationName: String?,
discipline: String?,
coordinate: CLLocationCoordinate2D
) {
self.title = title
self.locationName = locationName
self.discipline = discipline
self.coordinate = coordinate
super.init()
}
var subtitle: String? {
return locationName
}
}
为了符合MKAnnotation
, Artwork
必须子类化NSObject
,因为MKAnnotation
是一个NSObjectProtocol
。
MKAnnotation
需要coordinate
属性。如果您希望注释视图在用户点击标记时显示标题和副标题,那么您的类还需要名为title
和subtitle
的属性。
Artwork
类完全可以存储名为title
和coordinate
的属性,而不存储PublicArt.geojson
属性自然地映射到subtitle
。要符合MKAnnotation
,可以将subtitle
作为返回locationName
的计算属性。
MKAnnotation
协议属性title
和subtitle
被定义为可选的字符串,但是您可能想知道为什么要使用String?
作为locationName
和discipline
属性的类型。由于这些属性是从外部数据源PublicArt.geojson
设置文件,你不能保证它们总是存在。最好是安全一点。
你会使用MKAnnotation
对象的title,locationName
和coordinate
属性,但它的discipline
属性是什么呢?您将在本教程的后面找到答案!
2. Adding an Annotation
接下来,您将为您想要绘制的每个艺术品向地图视图添加一个Artwork
对象。现在,您只添加了一个artwork
,因此切换到ViewController.swift
并在viewDidLoad()
的末尾添加以下行:
// Show artwork on map
let artwork = Artwork(
title: "King David Kalakaua",
locationName: "Waikiki Gateway Park",
discipline: "Sculpture",
coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661))
mapView.addAnnotation(artwork)
在这里,您创建一个新的Artwork
对象,并将其作为注释添加到地图视图中。MKMapView
还提供了addAnnotations(_:)
,在本教程后面的内容中,当您有一个要添加到map
视图中的annotation
数组时,您将会用到它。
构建和运行。现在你可以看到大卫王卡拉卡瓦(King David Kalakaua)
的雕像就在Waikiki
的门口!
默认的annotation
标记视图显示标题位于标记下方的位置。选择标记。它变大,现在也显示子标题:
好吧,这没什么,但你已经看到,在其他应用程序中点击一个标记会显示一个标注(callout)
:一个小小的方形语音气泡。为此,您必须配置annotation
视图。
3. Configuring the Annotation View
配置annotation
视图的一种方法是实现map
视图的mapView(_:viewFor:)
代理方法。在这个代理方法中,您的工作是返回MKAnnotationView
的一个实例,作为annotation
的一个可视指示器。
在本例中,ViewController
是地图视图的代理。为了避免混乱和提高可读性,您将创建一个ViewController
扩展。
在ViewController.swift
的底部添加如下代码:
extension ViewController: MKMapViewDelegate {
// 1
func mapView(
_ mapView: MKMapView,
viewFor annotation: MKAnnotation
) -> MKAnnotationView? {
// 2
guard let annotation = annotation as? Artwork else {
return nil
}
// 3
let identifier = "artwork"
var view: MKMarkerAnnotationView
// 4
if let dequeuedView = mapView.dequeueReusableAnnotationView(
withIdentifier: identifier) as? MKMarkerAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
// 5
view = MKMarkerAnnotationView(
annotation: annotation,
reuseIdentifier: identifier)
view.canShowCallout = true
view.calloutOffset = CGPoint(x: -5, y: 5)
view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
return view
}
}
你要做的是:
- 1)
mapView(_:viewFor:)
在处理table view
时,对于添加到地图中的每一个annotation
都会被调用,比如tableView(_:cellForRowAt:)
,以返回每个注释的视图。 - 2) 你的应用可能会使用其他的注解,比如用户位置,所以检查这个注解是否是一个
Artwork
对象。如果不是,则返回nil
以允许地图视图使用其默认的注释视图。 - 3) 将每个视图创建为
MKMarkerAnnotationView
。在本教程的后面,您将创建MKAnnotationView
对象来显示图像,而不是标记。 - 4) 与
tableView(_:cellForRowAt:)
类似,地图视图重用了不再可见的注释视图。因此,在创建新注释视图之前,要检查是否有可重用的注释视图可用。当您将一个可重用的注释从队列中取出时,您给它一个标识符。如果您有多种类型的注释,请确保每种注释都有唯一的标识符。这和tableView(_:cellForRowAt:)
中的cell
标识符是一样的。 - 5) 在这里,如果无法将注释视图从队列中
dequeue
,则创建一个新的MKMarkerAnnotationView
对象。它使用Artwork
类的标题和副标题(title and subtitle)
属性来确定在callout
中显示什么。
4. The Map View Delegate
剩下的就是将ViewController
设置为map
视图的代理。你可以在Main.storyboard
中这样做。但如果你在代码中做,它更明显。在ViewController.swift
中,添加这一行到viewDidLoad()
,之前的声明,创建artwork
:
mapView.delegate = self
这是它!构建和运行。点击标记,弹出callout
气泡:
mapView(_:viewFor:)
将callout
配置为在右侧包含一个detail disclosure info
按钮,但是点击该按钮还没有完成任何操作。你可以实现它来显示一个包含更多信息的alert
或者打开一个细节视图控制器。
这是第三种选择。当用户点击信息按钮时,你的应用程序就会启动Maps
应用程序,完成从模拟用户位置到艺术品的驾驶、步行和交通指示!
Launching the Maps App
为了提供这一伟大的用户体验,打开Artwork.swift
并添加这一import
声明:
import Contacts
这将添加Contacts
框架,该框架包含字典键常量,如CNPostalAddressStreetKey
,用于在需要设置地址、城市或州字段时使用。
要告诉Maps
应用程序要去哪里,您必须传递一个MKMapItem
给它。这个类描述地图上的一个兴趣点。要创建一个,您必须首先创建一个MKPlacemark
来描述这个点。
接下来,将以下属性添加到类中:
var mapItem: MKMapItem? {
guard let location = locationName else {
return nil
}
let addressDict = [CNPostalAddressStreetKey: location]
let placemark = MKPlacemark(
coordinate: coordinate,
addressDictionary: addressDict)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
您可以使用现有的位置信息作为地址来创建MKPlacemark
。然后创建并配置与Maps
通信所需的MKMapItem
。
1. Handling the Callout
接下来,您必须告诉MapKit
当用户点击callout
按钮时应该做什么。打开ViewController.swift
。并将此方法添加到MKMapViewDelegate
扩展:
func mapView(
_ mapView: MKMapView,
annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl
) {
guard let artwork = view.annotation as? Artwork else {
return
}
let launchOptions = [
MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving
]
artwork.mapItem?.openInMaps(launchOptions: launchOptions)
}
当用户点击地图注释标记时,callout
显示一个info
按钮。如果用户点击这个信息按钮,iOS会调用mapView(_:annotationView: calloutAccessoryControlTap:)
。
在此方法中,获取此tap
引用的Artwork
对象,然后通过创建关联的MKMapItem
并在map item
上调用openInMaps(launchOptions:)
来启动Maps
。
注意,您正在向这个方法传递一个字典。这允许您指定几个不同的选项。这里,DirectionsModeKey
设置为Driving
。
这将导致Maps
显示从用户当前位置到此位置的驾驶方向。
注意:查看
MKMapItem
文档documentation以查看其他启动选项字典键和openMaps(with:launchOptions:)
方法,该方法允许您传递一个MKMapItem
对象数组。
2. Setting Your Simulated Location
在你构建和运行之前,你应该移动到Honolulu
。那么,只需将您的模拟位置设置为Honolulu
。
在Xcode
中,点击“Product►Scheme►Edit Scheme…”
,从左侧菜单中选择“Run”
,然后选择“Options”
选项卡。选中Allow Location Simulation
,并选择Honolulu, HI
,美国作为默认位置。然后点击Close
按钮:
构建和运行。你会看到Waikiki
的地图像以前一样放大了。点击标记,然后点击callout
中的info
按钮,就可以看到它启动Maps
,显示雕像的位置和前往雕像的驾驶方向:
这需要用你最喜欢的热带饮料来庆祝一下!
注意:当你第一次打开
Maps
时,它会提示你允许Maps
访问你的位置 —— 点击Allow While Using App
—— 并显示一个安全警告。
Decoding GeoJSON with MKGeoJSONDecoder
现在您已经知道了如何在地图上显示一个artwork
,以及如何从标记的callout
信息按钮启动Maps
,现在是时候将数据集解析为Artwork
对象数组了。然后将它们作为注释添加到地图视图中,以显示位于当前地图区域的所有艺术品。
MapKit
有MKGeoJSONDecoder
,这是一个非常有用的功能。它可以解码GeoJSON
数据并返回一个实现MKGeoJSONObject
协议的对象数组。MapKit
还提供了一个实现此协议的具体类:MKGeoJSONFeature
,这是本教程所需的全部内容。
将这个可失败的初始化程序添加到Artwork.swift
中,初始化器下方:
init?(feature: MKGeoJSONFeature) {
// 1
guard
let point = feature.geometry.first as? MKPointAnnotation,
let propertiesData = feature.properties,
let json = try? JSONSerialization.jsonObject(with: propertiesData),
let properties = json as? [String: Any]
else {
return nil
}
// 3
title = properties["title"] as? String
locationName = properties["location"] as? String
discipline = properties["discipline"] as? String
coordinate = point.coordinate
super.init()
}
你要做的是:
- 1)
MKGeoJSONFeature
具有表示与该特性关联的一个或多个形状的geometry
属性。PublicArt.geojson
的所有特点是点位置,MapKit
为您创建了一个MKPointAnnotation
。在这里,您可以找到作为CLLocationCoordinate2D
的坐标。 - 2) 接下来,读取特性的
properties
,哪些是Data?
类型并包含一个序列化的JSON
字典。使用JSONSerialization
将数据解码到一个Swift
字典中。 - 3) 现在已经对属性进行了解码,您可以从字典值中设置适当的
Artwork
属性。
1. Making Annotations
要使用这个初始化器,打开ViewController.swift
并添加以下属性,一个数组来保存来自GeoJSON
文件的Artwork
对象到类中:
private var artworks: [Artwork] = []
接下来,将以下helper
方法添加到类中:
private func loadInitialData() {
// 1
guard
let fileName = Bundle.main.url(forResource: "PublicArt", withExtension: "geojson"),
let artworkData = try? Data(contentsOf: fileName)
else {
return
}
do {
// 2
let features = try MKGeoJSONDecoder()
.decode(artworkData)
.compactMap { $0 as? MKGeoJSONFeature }
// 3
let validWorks = features.compactMap(Artwork.init)
// 4
artworks.append(contentsOf: validWorks)
} catch {
// 5
print("Unexpected error: \(error).")
}
}
以下是你在这段代码中要做的事情:
- 1) 首先,你要读取
PublicArt.geojson
转换为Data
对象。 - 2) 使用
MKGeoJSONDecoder
获取一个GeoJSON
对象数组,但仅使用compactMap
保存MKGeoJSONFeature
的实例。 - 3) 使用添加的可失败初始化器将
MKGeoJSONFeature
对象转换为Artwork
对象,并再次使用compactMap
。 - 4) 将产生的
validWorks
添加到artworks
数组中。 - 5) 因为
MKGeoJSONDecoder
的decode(_:)
方法会抛出一个错误,所以您可以捕获它并将错误打印到Xcode控制台。
Plotting the Artwork
您现在在数据集中有了一个所有公共artwork
的数组,您将把它添加到地图中。
还在ViewController.swift
中,在viewDidLoad()
结尾添加以下代码:
loadInitialData()
mapView.addAnnotations(artworks)
注意:一定要使用复数形式的
addAnnotations
,而不是单数形式的addAnnotation
!
删除创建单个King David Kalakaua
地图注释的行。loadInitialData()
创建了artworks
数组,现在不需要它们了。
构建和运行。检查所有的标记!
移动地图,可以看到其他标记出现。点击一个标记来打开它的callout
气泡,然后点击它的信息按钮来启动Maps
。是的,你对卡拉卡瓦国王雕像所做的一切都与所有新的artwork
有关!
如果您担心在不可见的情况下向地图添加注释,请不要这样做!苹果建议立即添加所有注释Apple recommends adding all the annotations right away,无论它们在地图区域是否可见。当您移动地图时,它会自动显示可见的注释。
现在,您已经构建了一个应用程序,该应用程序将一个GeoJSON
文件解析为一个artworks
数组,然后将其作为注释标记显示,并带有一个callout
信息按钮来启动Maps
。
但等一下,还有一些亮点要添加。
Customizing Annotations
还记得Artwork
类中的discipline
属性吗?它的值比如Sculpture
和 Mural
。事实上,最多的discipline
是Sculpture, Plaque, Mural and Monument
。
标记的颜色编码很容易,所以大多数学科都有自己的彩色标记,而所有其他的disciples
都有绿色标记。
1. Markers with Color-Coding and Text
在Artwork.swift
中,添加此属性:
var markerTintColor: UIColor {
switch discipline {
case "Monument":
return .red
case "Mural":
return .cyan
case "Plaque":
return .blue
case "Sculpture":
return .purple
default:
return .green
}
}
现在,您可以继续向mapView(_:viewFor:)
添加代码,但这会使视图控制器变得混乱。还有一种更优雅的方法,类似于您可以为table view
单元格所做的事情。创建一个名为ArtworkViews.swift
的新Swift
文件,并在import
语句下面添加以下代码:
import MapKit
class ArtworkMarkerView: MKMarkerAnnotationView {
override var annotation: MKAnnotation? {
willSet {
// 1
guard let artwork = newValue as? Artwork else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
// 2
markerTintColor = artwork.markerTintColor
if let letter = artwork.discipline?.first {
glyphText = String(letter)
}
}
}
}
很快,您将把这个类注册为Artwork
注释的可重用注释视图。系统将一个注释作为newValue
传递给它,你要做的是:
- 1) 这些行执行与
mapView(_:viewFor:)
相同的操作,配置callout
。 - 2) 然后设置标记的
tint
颜色,并将其pin
图标或字形替换为注释discipline
的第一个字母。
2. Color My World
现在切换到ViewController.swift
。在调用loadInitialData()
之前,将这行代码添加到viewDidLoad()
:
mapView.register(
ArtworkMarkerView.self,
forAnnotationViewWithReuseIdentifier:
MKMapViewDefaultAnnotationViewReuseIdentifier)
在这里,您使用地图视图的默认重用标识符注册新类。对于具有更多注释类型的应用程序,可以使用自定义标识符注册类。
向下滚动扩展并删除mapView(_:viewFor:)
。
构建和运行。然后移动地图,看看不同的颜色和标记标记:
在地图的这一部分,有更多比地图视图显示的艺术。它通过将过于接近的标记聚类来减少混乱。在下一节中,您将看到所有注释。
但是首先,设置字形的图像而不是它的文本。添加以下属性到Artwork.swift
:
var image: UIImage {
guard let name = discipline else {
return #imageLiteral(resourceName: "Flag")
}
switch name {
case "Monument":
return #imageLiteral(resourceName: "Monument")
case "Sculpture":
return #imageLiteral(resourceName: "Sculpture")
case "Plaque":
return #imageLiteral(resourceName: "Plaque")
case "Mural":
return #imageLiteral(resourceName: "Mural")
default:
return #imageLiteral(resourceName: "Flag")
}
}
这些来自icons8.com的图片已经在Assets.xcassets
中了。
然后,在ArtworkMarkerView.swift
,将glyphText
行替换为:
glyphImage = artwork.image
构建和运行看到不同的彩色标记与图像:
这是另一个定制选项的segue
你的下一个任务:用图像替换标记!
3. Annotations with Images
在ArtworkViews.swift
,添加以下类:
class ArtworkView: MKAnnotationView {
override var annotation: MKAnnotation? {
willSet {
guard let artwork = newValue as? Artwork else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
image = artwork.image
}
}
}
现在,您使用的是一个普通的旧MKAnnotationView
,而不是MKMarkerAnnotationView
,而且该视图有一个image
属性。
回到ViewController.swift
中。在viewDidLoad()
中,注册这个新类,而不是ArtworkMarkerView
:
mapView.register(
ArtworkView.self,
forAnnotationViewWithReuseIdentifier:
MKMapViewDefaultAnnotationViewReuseIdentifier)
构建并运行以看见所有的图标
4. Custom Callout Accessory Views
右边的callout
附件是一个信息按钮,但是点击它会打开Maps
。现在,您将更改按钮以显示Maps
图标。
在ArtworkView
中找到这一行:
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
用以下代码替换这一行:
let mapsButton = UIButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 48, height: 48)))
mapsButton.setBackgroundImage(#imageLiteral(resourceName: "Map"), for: .normal)
rightCalloutAccessoryView = mapsButton
这里,你创建一个UIButton
,设置它的背景图像为一个地图图标,也来自于Assets.xcassets
中的icons8.com。然后将视图的右侧callout
附件设置为此按钮。
构建和运行。然后点击一个视图来查看新的Maps
按钮:
最后的定制是detail callout
附件。这是一个单一的行,这是足够短的位置文本,但一些较长的位置值被截断如下:
现在您需要一个多行标签。添加以下代码到ArtworkView
的willSet
:
let detailLabel = UILabel()
detailLabel.numberOfLines = 0
detailLabel.font = detailLabel.font.withSize(12)
detailLabel.text = artwork.subtitle
detailCalloutAccessoryView = detailLabel
构建和运行。然后点击一个视图来查看完整的长位置文本。
现在您已经了解了使用MapKit
的基础知识,但是您还可以添加更多内容:地图显示自定义、地理编码、地理围栏、自定义地图覆盖等等。 MapKit documentation、Location and Maps Programming Guide是查找更多信息的好地方。
还可以看看WWDC 2019 Session 236: What’s New in MapKit and MapKit JS,以发现更多的酷功能添加到iOS 13
中。
后记
本篇主要介绍了地图特定区域放大和创建自定义地图
annotations
,感兴趣的给个赞或者关注~~~
网友评论