版本记录
版本号 | 时间 |
---|---|
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
访问您的位置(点按允许),并显示安全警告。
后记
本篇主要讲述了基本使用简单示例,感兴趣的给个赞或者关注~~~