热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MapKit使用介绍:大头针和图形渲染

作者:PRANJALSATIJA,原文链接,原文日期:2016-11-13译者:TonyHan;

作者:PRANJAL SATIJA,原文链接,原文日期:2016-11-13
译者:TonyHan;校对:Cwift;定稿:CMB

最近 APP 中的地图功能变得越来越流行了。从优步到 Instagram ,再到我的新应用 peek ,地图功能在各种 APP 中都能见到。虽然地图很常见,但是往地图功能添加一些更复杂的功能还是有点挑战的。在这篇文章中,咱们就讨论下在 MapKit 中的大头针和图形渲染,MapKit 是苹果 iOS 系统中的地图库。你在 iOS 系统中看到的许多地图都依赖 MapKit 的强大支撑——当然包括苹果内置地图 APP!MapKit 是一个功能强大、稳定的、健壮的地图库。当然它也很易用,让我们开始吧!

准备工作

开始之前,请先下载实例程序。打开之后你会发现这些文件:

  • Places.plist:这是存储我们要渲染的坐标信息的配置文件。

  • Places.swift:这个 swift 文件加载 Places.plist 文件中的数据并暴露给其他代码。

  • Main.storyboard:这是我们应用使用的主 storyboard 。里面是一个带有地图视图的视图控制器。我已经搭建好界面和约束了。

  • ViewController.swift:这是用于控制地图的试图控制器。我已经创建好一个连线来连接 storyboard 中的地图视图。

在构建运行应用之前,还有一件事情需要做:导入 MapKit.framework 到我们项目中,这样才能使用 MapKit。有两种方式:一种是手动添加依赖库。点击项目导航中的 MapKit starter ,向下滚动到 Linked Frameworks and Libraries :

点击加号图标添加 MapKit.framework。如果 Embedded Binaries 中没有自动添加,则在此处也要点击加号添加。

或者,你可以去 Capabilities 界面将 Maps 选项设置为 ON

现在我们已经准备完毕!编译并运行应用看看会效果!你将会看到 MKMapView 占据了整个屏幕。默认情况下,地图视图支持放大、旋转、滚动以及 3D 模式。它还显示有趣的地点,并在主要城市以 3D 显示建筑物。相当酷吧!这篇文章中我们将使用这个地图,泡杯咖啡坐下来,一起进行这项工作吧!

用户坐标展示

首先,将用户的坐标展示到地图上是很重要的,这样用户就可以对其所在位置周围的建筑有所感知。很幸运,用 MapKit 很容易做到这一点。打开 Storyboard,选择我们的地图,勾选 User Location 这一项:

如果你想通过代码实现,把下面这一行放到控制器中的 viewDidLoad 方法中:


mapView?.showsUserLocation = true

在达到目标前还有几步要完成。现在,MapKit 将会展示用户的位置,但我们还没有申请用户授权。我们来完成这个。

打开 ViewController.swift 并且添加一个方法 requestLocationAccess():


func requestLocationAccess() {let status = CLLocationManager.authorizationStatus()switch status {case .authorizedAlways, .authorizedWhenInUse:returncase .denied, .restricted:print("location access denied")default:locationManager.requestWhenInUseAuthorization()}
}

这个方法实现一个简单的目标:检查用户是否授权使用位置并作出响应。如果用户已经授权过,那直接返回,不再有其他操作。如果用户拒绝或限制位置信息使用,则会输出错误信息。否则,我们在应用中会向用户申请使用位置信息。

最后一件事。找到 Info.plist 文件。增加一个类型为 String 的键 NSLocationWhenInUseUsageDescription,然后设置值为 MapKit starter needs your location so that you can see it on a map.。通过这个可以告诉用户我们为什么要去请求使用位置信息,从而让用户更倾向于同意访问。从 iOS 8 开始,系统要求我们必须添加这段字符信息。

还有一步!在 ViewController.swift 中重写 viewDidLoad() 方法并调用 requestLocationAccess() 方法:


override func viewDidLoad() {requestLocationAccess()
}

再一次编译并运行应用。你会得到一个获取用户信息的提示。点击接受,然后看着吧。现在会显示出你所在的位置。MapKit 会随着用户位置的移动而自动更新坐标。

如果你在用模拟器测试应用,你可以点击调试区域的位置按钮,Xcode 提供了一系列位置信息来模拟用户的位置。

现在让我们试试显示更牛逼的内容吧。

展示自定义大头针

我们已经知道如何展示用户的坐标了,但是现在,我们需要展示用我们的自己的图片自定义的大头针样式。打开 Places.plist 文件,查看其内容。你能看到一个简短的城市列表。由于只是个例子,我们并没有准备太多数据。

html



titleNew YorkdescriptionWelcome to New York City!latitude40.7128longitude-74.0059titleSan FranciscodescriptionWelcome to San Francisco!latitude37.7749longitude-122.4194titleLos AngelesdescriptionWelcome to Los Angeles!latitude34.0522longitude-118.2437


列表里有纽约、旧金山和洛杉矶及其经纬度坐标。虽然有关配置文件的知识已经超出了本篇教程的范围,但是你可以在这篇文章里找到关于 .plist 配置文件的内容。

打开 Places.swift 文件,你会看到一个静态方法,用来获取 Places.plist 文件中的所有地点。你不用关心实现,你只需要去调用 Place.getPlaces() 方法,便可以返回 Places.plist 中的所有地点。让我们在 ViewController 中添加一个属性,用来保存所有已加载的地点信息:


let places = Place.getPlaces()

确保 ViewController.swift 中的代码如下:


import UIKit
import MapKitclass ViewController: UIViewController {@IBOutlet var mapView: MKMapView?let locationManager = CLLocationManager()let places = Place.getPlaces()override func viewDidLoad() {requestLocationAccess()}func requestLocationAccess() {let status = CLLocationManager.authorizationStatus()switch status {case .authorizedAlways, .authorizedWhenInUse:returncase .denied, .restricted:print("location access denied")default:locationManager.requestWhenInUseAuthorization()}}
}

现在,让我们看看关键的地方。下面是在 MKMapView 上添加大头针的基本流程:

  1. 创建遵从 MKAnnotation 协议的对象,扩展已存在的对象也可以。

  2. 通过 addAnnotation(_:) 在一个 MKMapView 实例中添加大头针对象。

  3. 创建遵从 MKMapViewDelegate 协议的对象并指定其代理为我们的地图视图。

  4. 实现 mapView(_: viewFor:) 方法,为 MapKit 提供需要渲染的大头针视图。

下面我们会实现上面的四个步骤。

创建遵从 MKAnnotation 协议的对象

MKAnnotation 协议定义在 MapKit 中,用来给 MapKit 提供数据。我们来实现 MKAnnotation 协议的要求:


var title: String?
var subtitle: String?
var location: CLLocationCoordinate2D

任何用来保存或展示大头针的自定义对象都可以通过遵守 MKAnnotation 协议从而使用相关的功能。随后每个对象都会作为地图上大头针的数据源,提供关键的信息,比如大头针在地图上的位置。

如你所料,我们扩展 Place 类并遵从 MKAnnotation 协议。在 Place.swift 中导入 MapKit 并添加 MKAnnotation 协议:


extension Place: MKAnnotation { }

编译并运行,啥东西也没有。这是正常的。同时,我们的 Place 类也已满足 MKAnnotation 的所有的要求。

很好。让我们接着做下一步。

向地图视图添加大头针

这步不难。我们只需要告诉 mapView 我们已经加载的每一个地点即可。在 ViewController.swift 中添加一个方法。命名为 addAnnotations():


func addAnnotations() {mapView?.delegate = selfmapView?.addAnnotations(places)
}

这并不复杂。将地图视图的代理设置成 self。然后,我们将地点大头针添加到地图上。简单吧!继续之前记得在 viewDidLoad() 中调用 addAnnotations() 方法。

遵守 MKMapViewDelegate 协议

接下来我们需要创建一个遵守 MKMapViewDelegate 协议的对象。跟 MKAnnotation 协议一样,我们需要扩展一个类来实现。如果你之前用过 UITableView,那这跟使用 UITableViewDelegateUITableViewDataSource 相似。我们使用 ViewController 的扩展来实现 MKMapViewDelegate 协议:


extension ViewController: MKMapViewDelegate {func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {}
}

上面的代码扩展了 ViewController 类,并且添加了向每个大头针返回相应视图的方法。让我们继续:


func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {if annotation is MKUserLocation {return nil}else {let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotationView") ?? MKAnnotationView()annotationView.image = UIImage(named: "place icon")return annotationView}
}

很简单是吧?首先我们检查一下大头针是否展示在了用户位置上。如果是,我们不用返回自定义大头针,因为我们希望和往常一样来展示用户的位置。如果没有的话,我们新建一个大头针,我们通过 **[复用队列
](https://en.wiktionary.org/wik...** 来创建一个新的大头针。这样我们就能有效的复用大头针视图。然后,我们设置大头针视图上的图片(在 Assets.xcassets 中使用的图片)。最后,我们返回大头针视图。

审查代码

看下 ViewController.swift 文件。如果你按照步骤做完,那代码应该是这样的:


import UIKit
import MapKitclass ViewController: UIViewController {@IBOutlet var mapView: MKMapView?let locationManager = CLLocationManager()let places = Place.getPlaces()override func viewDidLoad() {requestLocationAccess()addAnnotations()}func requestLocationAccess() {let status = CLLocationManager.authorizationStatus()switch status {case .authorizedAlways, .authorizedWhenInUse:returncase .denied, .restricted:print("location access denied")default:locationManager.requestWhenInUseAuthorization()}}func addAnnotations() {mapView?.delegate = selfmapView?.addAnnotations(places)}
}extension ViewController: MKMapViewDelegate {func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {if annotation is MKUserLocation {return nil}else {let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotationView") ?? MKAnnotationView()annotationView.image = UIImage(named: "place icon")return annotationView}}
}

运行应用,你会发现地图中有三个大头针分别对应 Place.plist 文件中指定的地点。

如果没成功,请往前查看是否遗漏了某一步。如果需要帮助请随时留言。现在我们已经掌握了向 MKMapView 添加了大头针的技巧。peek 中就是用这样的方式向用户展示事件发生的位置。大多数带地图功能的应用都使用这个技术来向用户展示指定的地点。

现在我们来看看如何添加图层渲染。

展示图层渲染

目前为止,我们已经学会如何展示自定义的大头针以便标注出地图上的地点。接下来我们来学习在地图上绘出图形。例如,我们可能会在每个地点周围画出半径 100 米圆。为了实现这点,我们需要做两件事:

1.在我们的地图上添加遮罩。
2.为每个遮罩指定渲染器,让 MapKit 去渲染这些图层。

添加遮罩

首先,需要告诉 MapKit 我们想在地图上展示遮罩。修改 addAnnotations(),如下:


func addAnnotations() {mapView?.delegate = selfmapView?.addAnnotations(places)let overlays = places.map { MKCircle(center: $0.coordinate, radius: 100) }mapView?.addOverlays(overlays)
}

前两行很相似,后面两行代码是新的。我们使用 map —— Swift 的集合操作函数,来生成一个基于我们的地点的 MKCircle 对象数组。如果你对 map 感到陌生,可以理解为 for 循环。但是你可以一行代码实现。

接下来,通过 mapView?.addOverlays(_:) 添加遮罩。跟添加大头针类似。

渲染遮罩

添加遮罩还不够。你只有渲染并设置可见,MapKit 才会去显示这些遮罩。我们对每个地点添加了圆形的遮罩,对应地要对遮罩进行渲染。在 ViewController 扩展中添加 mapView(_: rendererFor:) 方法:


func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {let renderer = MKCircleRenderer(overlay: overlay)renderer.fillColor = UIColor.black.withAlphaComponent(0.5)renderer.strokeColor = UIColor.bluerenderer.lineWidth = 2return renderer
}

正如名字所显示的,这个方法允许我们返回 MKOverlayRenderer ,为每个遮罩提供合适的渲染。MapKit 对于圆形的渲染有一个类,叫做 MKCircleRenderer。我们创建一个渲染器,并且设置成想要的外观,并将其返回, MapKit 就可以使用渲染器了。

现在你可以再次测试应用。放大纽约、旧金山或洛杉矶,能看到圆形的遮罩。

总结

通过这篇文章我们学到了很多关于大头针和图形渲染的知识。用这些知识武装自己,你应该能够开发一个带有优雅地图的应用了吧!有啥问题随时都可以评论。

另外,你可以从 GitHub 上下载 Xcode 项目来参考。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。




推荐阅读
  • 添加#import头文件倒入mapkit.framework库mapkit.framework是属于ui,可以在故事版上添加mkmap ... [详细]
  • Android native层服务例子Bp和Bn
    转入android阵地,被各种权限所阻挠,app写个jni各种没有权限,只能开个native服务,本来android的服务& ... [详细]
  • Iwanttointegratesort,order,maxandoffsetinafindAllquery.Thefollowingworksfine:我想在fin ... [详细]
  • 在iOS6之后,不再使用谷歌地图了,而是使用苹果自己的地图,但是API编程接口没有太大的变化。开发人员不需要再学习很多新东西就能开发地图应用,这是负责任的做法。因此本节介绍的内容也同样适用于iOS5 ... [详细]
  • IOS9之当前位置定位
    2019独角兽企业重金招聘Python工程师标准#import*.h文件中导入以下两个框架*#import ... [详细]
  • IOS笔记汇总为了方便开发者开发出强大的功能,苹果提供了各种各样的框架IOS属性IOS基础属性导入依赖propertyNSStringNSDictionaryNSAr ... [详细]
  • switch语句的一些用法及注意事项
    本文介绍了使用switch语句时的一些用法和注意事项,包括如何实现"fall through"、default语句的作用、在case语句中定义变量时可能出现的问题以及解决方法。同时也提到了C#严格控制switch分支不允许贯穿的规定。通过本文的介绍,读者可以更好地理解和使用switch语句。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
夜幕下的猫眼_398
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有