热门标签 | 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。




推荐阅读
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 本文介绍了PHP常量的定义和使用方法,包括常量的命名规则、大小写敏感性、全局范围和标量数据的限制。同时还提到了应尽量避免定义resource常量,并给出了使用define()函数定义常量的示例。 ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
  • 本文介绍了在Java中检查字符串是否仅包含数字的方法,包括使用正则表达式的示例代码,并提供了测试案例进行验证。同时还解释了Java中的字符转义序列的使用。 ... [详细]
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社区 版权所有