版本记录
| 版本号 | 时间 |
|---|---|
| V1.0 | 2018.10.14 星期日 |
前言
MapKit框架直接从您的应用界面显示地图或卫星图像,调出兴趣点,并确定地图坐标的地标信息。接下来几篇我们就一起看一下这个框架。感兴趣的看下面几篇文章。
1. MapKit框架详细解析(一) —— 基本概览(一)
开始
首先看一下本文的写作环境
Swift 4, iOS 11, Xcode 9
MapKit是iOS设备上非常有用的API,可以轻松显示地图,绘制位置,甚至在上面绘制路线和其他形状。
此更新使用来自檀香山的公共艺术品数据。在本教程中,您将制作一个放大檀香山位置的应用程序,并在地图上绘制其中一件作品。 您将实施pin的标注详细信息按钮以启动Maps应用程序,其中包含对艺术品的驾驶/步行路线。 然后,您的应用程序将从Honolulu数据门户解析JSON文件,以提取公共艺术品对象,并在地图上绘制它们。
在此过程中,您将学习如何将MapKit地图添加到您的应用程序,缩放到特定位置,解析使用Socrata Framework的政府数据,创建自定义地图annotations等等!
打开入门项目,其中包含JSON文件和一些图像资源,但还没有地图!
打开Main.storyboard。 在File Inspector中,选中Use Safe Area Layout Guides框。 这将阻止您设置相对于已弃用的布局指南的约束,并停止deprecated警告。

在Document Outline中,选择Safe Area,以查看其上边缘略低于视图的上边缘。 从Object library中,将MapKit View拖动到场景的上角,将其顶部边缘与视图顶部边缘下方的蓝色虚线对齐,然后拖动其右下角以与视图的右下角相交。 使用Add New Constraints自动布局菜单(TIE战斗机图标)固定地图视图:取消选中Constrain to margins,然后将所有邻值设置为0,并单击Add 4 constraints:

注意:通常情况下,您不必手动将地图视图拉伸到场景中 - 只需使用Add New Constraints菜单来固定其边缘 - 但这在Xcode 9 beta中尚未使用。现在Xcode 10都出来了,所以这个问题已经不存在了。
接下来,将此行添加到ViewController.swift,就在import UIKit语句的下方:
import MapKit
Build并运行您的项目,您将拥有一个完全可缩放和可平移的地图,使用Apple Maps显示您当前位置的大陆!

到目前为止这么好,嗯? 但是你不想开始查看整个世界的地图 - 你想放大到一个特定的区域!
要控制地图视图,必须在ViewController.swift中为其创建outlet。
在故事板中,打开assistant editor:它应该显示ViewController.swift。
要创建outlet,请单击Main.storyboard中的Map View,然后按住control - 拖动到ViewController类定义内的空间:Xcode应提示Insert Outlet or Outlet Collection。 释放拖动,然后在弹出窗口中为outlet命名为mapView:

Xcode将一个mapView属性添加到ViewController类:您将使用它来控制地图视图显示的内容。
Setting Visible Area - 设置可见区域
切换回standard editor,在ViewController.swift中找到viewDidLoad(),并将以下内容添加到方法的末尾:
// set initial location in Honolulu
let initialLocation = CLLocation(latitude: 21.282778, longitude: -157.829444)
您将使用它将地图视图的起始坐标设置为檀香山的一个点。
在告诉地图要显示的内容时,给出纬度和经度足以使地图居中,但您还必须指定要显示的矩形区域,以获得正确的缩放级别。
将以下常量和辅助方法添加到类中:
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius, regionRadius)
mapView.setRegion(coordinateRegion, animated: true)
}
location参数是中心点。 该区域将根据区域的距离而具有南北和东西跨度。 您将其设置为1000米:稍微超过半英里,这适用于在JSON文件中绘制艺术品数据。
setRegion(_:animated :)告诉mapView显示该区域。 地图视图使用简洁的缩放动画自动将当前视图转换到所需区域,无需额外代码!
回到viewDidLoad(),将以下行添加到方法的末尾:
centerMapOnLocation(location: initialLocation)
您正在调用辅助方法以在启动时放大initialLocation。
Build并运行应用程序,您将发现自己位于Waikiki(地名)的中心。

Obtaining Public Artworks Data - 获取公共艺术品数据
下一步是在当前位置周围绘制有趣的数据。但是在哪里可以得到这样的东西?
那么,这取决于你当前的位置。与许多城市一样,檀香山有一个 Open Data Portal,可以改善公众对政府数据的访问。与许多城市一样,檀香山的数据门户是Socrata提供支持的,这是一个开放的数据框架,提供了一组丰富的developer tools,用于访问基于Socrata的数据。完成本教程后,可以查看附近的城市是否有可以使用的备用数据集?
在本教程中,您将使用Honolulu Public Art。为了简单起见,我已经从门户网站下载了这些数据,并将其包含在项目中。
要了解此数据集中的项目,请在Xcode编辑器中打开PublicArt.json,然后向下滚动到第1180行(或使用⌘+ L表示跳转到行),以“data”开头,后跟数组数组 - 每个艺术品一个数组。对于本教程,您将仅使用每个数组中的一些属性:艺术作品的location name, discipline, title, latitude and longitude。例如,对于第一个数据项:
-
location name - 地点名称:
Lester McCoy Pavilion -
discipline:
Mural -
title - 标题:
The Makahiki Festival – The Makai Mural -
latitude - 纬度:
21.290824 -
longitude - 经度:
-157.85131
在本教程的后面,您将解析此数据集以创建一艺术作品数组,但首先,要直接跳转到MapKit,您只需在地图上绘制其中一件作品。
Showing an Artwork on the Map - 在地图上显示艺术品
在PublicArt.json中,跳转或滚动到第1233行的项目55:它是威基基盖特威公园的大卫卡拉卡瓦国王的青铜雕像。

该项目的属性是:
- location name - 地点名称:威基基盖特威公园
- discipline:雕塑
- title - 标题:大卫卡拉卡瓦国王
-
latitude - 纬度:
21.283921 -
longitude - 经度:
-157.831661
要在地图视图上显示此内容,您必须创建map annotation。 map annotation是绑定到特定位置的小块信息,并且通常在Apple的Maps应用中表示为pins。
要创建自己的annotations,可以创建符合MKAnnotation协议的类,将annotations添加到地图,并通知地图应如何显示annotations。
1. The Artwork Class - Artwork类
首先,在新的Swift文件中创建一个Artwork类:File \ New \ File,选择iOS \ Source \ Swift File,然后单击Next。 将Save As设置为Artwork.swift,然后单击Create。
在编辑器中打开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属性。 如果您希望annotation view在用户点击pin时显示标题和副标题,则您的类还需要名为title和subtitle的属性。
对于Artwork类来说,存储名为title和coordinate的属性是完全明智的,但是没有一个PublicArt.json属性自然地映射到subtitle的概念。 要符合MKAnnotation协议,您可以使subtitle成为返回locationName的计算属性。
好的,所以title, locationName和coordinate属性将用于MKAnnotation对象,但是discipline属性用来做什么?你会在本教程的后面找到!
2. Adding an Annotation - 添加注释
接下来,您将为地图视图添加一个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对象,并将其作为annotation添加到地图视图中。 MKMapView类还有一个addAnnotations :(复数)方法,当你有一个annotation数组要添加到地图视图时,你将在本教程的后面使用它。
Build并运行你的项目,现在你应该看到King David Kalakaua的雕像在Waikiki的入口处!

默认annotation标记视图显示位置,标记下方是标题。 选择标记:它会变大,现在也会显示副标题:

嗯,没关系,但是当用户点击标记时,你习惯于显示标注的pins - 一个小气泡。 为此,您必须配置annotation视图,这是下一步。
3. Configuring the Annotation View - 配置注释视图
配置annotation视图的一种方法是实现地图视图的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 = "marker"
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 :)会为您添加到地图的每个annotation调用(就像使用表视图时的tableView(_:cellForRowAt :)一样),以返回每个annotation的视图。 - 2) 您的应用可能会使用其他
annotation,例如用户位置,因此请检查此annotation是否为Artwork对象。 如果不是,则返回nil以使地图视图使用其默认annotation视图。 - 3) 要显示标记,可以将每个视图创建为
MKMarkerAnnotationView。 在本教程的后面,您将创建MKAnnotationView对象,以显示图像而不是标记。 - 4) 与
tableView(_:cellForRowAt :)类似,地图视图也会重用不再可见的annotation视图。 因此,在创建新的annotation视图之前,请检查是否可以使用可重用的annotation视图。 - 5) 如果
annotation视图无法重用出列,则在此处创建新的MKMarkerAnnotationView对象。 它使用Artwork类的标题和副标题属性来确定要在标注中显示的内容。
注意:有一点需要注意的事情,由
Kalgar建议,当你将可重复使用的annotation出列时,你给它一个标识符。 如果您有多种annotation样式,请确保每个annotation都有唯一的标识符,否则您可能会错误地将其他类型的标识符出列,并在您的应用中出现意外行为。 同样,它与tableView(_:cellForRowAt :)中的单元标识符背后的想法相同。
剩下的就是将ViewController设置为地图视图的代理。 您可以在Main.storyboard中执行此操作,但我更喜欢在代码中执行此操作,它更加明显。 在ViewController.swift中,在创建artwork的语句之前,将此行添加到viewDidLoad():
mapView.delegate = self
就是这样! Build并运行项目,然后点击标记以弹出标注气泡:

mapView(_:viewFor :)将标注配置为在右侧包含详细信息披露信息按钮,但点击该按钮尚未执行任何操作。 您可以实现它以显示包含更多信息的alert弹窗,或者打开详细视图控制器。
这是一个很好的第三个选项:当用户点击信息按钮时,您的应用程序将启动Maps应用程序,完成驾驶/步行/公交路线,从模拟用户位置到艺术品!
Launching the Maps App - 启动Maps应用程序
要提供这种出色的用户体验,请打开Artwork.swift并在其他两个下面添加此import语句:
import Contacts
这将添加Contacts框架,其中包含字典键常量,例如CNPostalAddressStreetKey,用于需要设置位置的地址,城市或州字段。
接下来,将以下辅助方法添加到类中:
// Annotation right callout accessory opens this mapItem in Maps app
func mapItem() -> MKMapItem {
let addressDict = [CNPostalAddressStreetKey: subtitle!]
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDict)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = title
return mapItem
}
在这里,您可以从MKPlacemark创建MKMapItem。 地图应用程序能够读取此MKMapItem,并显示正确的内容。
接下来,您必须告诉MapKit当用户点击callout按钮时该怎么做。 打开ViewController.swift,并将此方法添加到MKMapViewDelegate扩展:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
let location = view.annotation as! Artwork
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
location.mapItem().openInMaps(launchOptions: launchOptions)
}
当用户点击地图annotation标记时,标注会显示一个信息按钮。如果用户点击此信息按钮,则调用mapView(_:annotationView:calloutAccessoryControlTapped :)方法。
在此方法中,您将获取此点击要引用的Artwork对象,然后通过创建关联的MKMapItem并在map item上调用openInMaps(launchOptions :)来启动Maps应用。
请注意,您正在将字典传递给此方法。这允许您指定几个不同的选项;这里DirectionModeKey设置为Driving。这会导致Maps应用显示从用户当前位置到此pin的行车路线。
注意:浏览MKMapItem documentation以查看其他启动选项字典键,以及
openMaps(with:launchOptions :)方法,该方法允许您传递MKMapItem对象数组。
在你Build和运行之前,你应该搬到檀香山 - 实际上,只需将你的模拟位置设置为檀香山。在Xcode中,转到Product \ Scheme \ Edit Scheme ...,从左侧菜单中选择Run,然后选择Options选项卡。检查Core Location: Allow Location Simulation,并选择Honolulu, HI, USA作为Default Location。然后单击Close按钮:

Build并运行应用程序,您将看到地图放大Waikiki,就像之前一样。 点击标记,然后点击标注中的info按钮,并观看它启动Maps应用以显示雕像的位置,并显示其行车路线:

注意:首次打开
Maps时,系统会提示您允许Maps访问您的位置(点按允许),并显示安全警告。
后记
本篇主要讲述了基本使用简单示例,感兴趣的给个赞或者关注~~~
