导航
导航-简介
概念
简单来说, 就是根据用户指定的位置, 进行路线规划; 然后根据用户在行走过程中, 实时的给出指引提示
导航的三种实现方案
- 可以将需要导航的位置丢给系统的地图APP进行导航
- 发送网络请求到公司服务器获取导航数据, 然后自己手动绘制导航
- 利用三方SDK实现导航(百度)
使用系统地图App进行导航
利用"反推法", 记住关键代码即可
根据 MKMapItem 数组 和 启动参数字典 来调用系统地图进行导航
[MKMapItem openMapsWithItems:@[item1, item2] launchOptions:launchDic];
注意: CLPlacemark地标对象没法直接手动创建, 只能通过(反)地理编码获取
import MapKit
class ViewController: UIViewController {
lazy var geoCoder:CLGeocoder = {
return CLGeocoder()
}()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
geoCoder.geocodeAddressString("西宁") { (pls:[CLPlacemark]?, error:Error?) in
let xiningPL = pls?.first
self.geoCoder.geocodeAddressString("兰州") { (pls:[CLPlacemark]?, error:Error?) in
let lanzhouPL = pls?.first
self.startNav(startPLCL: xiningPL!, endPLCL: lanzhouPL!)
}
}
}
func startNav(startPLCL:CLPlacemark,endPLCL:CLPlacemark) {
//设置起点
let startMark:MKPlacemark = MKPlacemark(placemark: startPLCL)
let startItem:MKMapItem = MKMapItem(placemark: startMark)
//设置终点
let endMark:MKPlacemark = MKPlacemark(placemark: endPLCL)
let endItem:MKMapItem = MKMapItem(placemark: endMark)
//设置起点和终点的数组
let mapItems:[MKMapItem] = [startItem, endItem]
//导航设置字典
//MKLaunchOptionsDirectionsModeKey 导航模式
//MKLaunchOptionsMapTypeKey 地图样式
//MKLaunchOptionsShowsTrafficKey 显示交通
let dict = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey: MKMapType.standard.rawValue,
MKLaunchOptionsShowsTrafficKey: true] as [String : Any];
MKMapItem.openMaps(with: mapItems, launchOptions: dict)
}
}
导航-方案2-发送网络请求给苹果服务器获取导航路线
实现须知
- 获取导航路线, 需要想苹果服务器发送网络请求
- 记住关键对象MKDirections
另外,本示例会在地图上绘制路线图层
import UIKit
import MapKit
class ViewController: UIViewController {
@IBOutlet weak var mapView: MKMapView!
lazy var geoCoder:CLGeocoder = {
return CLGeocoder()
}()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
mapView.delegate = self
geoCoder.geocodeAddressString("西宁") { (pls:[CLPlacemark]?, error:Error?) in
if error == nil {
let xiningPl = pls?.first
// 添加一个圆形的覆盖层
// 1. 创建圆形的覆盖层数据模型
let xiningCircle = MKCircle(center: (xiningPl?.location?.coordinate)!, radius: 500000)
// 2. 添加覆盖层数据模型到地图上
self.mapView.add(xiningCircle)
// 3. 地图就会调用一个代理方法, 查找覆盖层视图
self.geoCoder.geocodeAddressString("阜康") { (pls:[CLPlacemark]?, error:Error?) in
if error == nil {
let wlmqPl = pls?.first
let wlmqCircle = MKCircle(center: (wlmqPl?.location?.coordinate)!, radius: 500000)
self.mapView.add(wlmqCircle)
self.getRouteMessage(startCLPL: xiningPl!, endCLPL: wlmqPl!)
}
}
}
}
}
func getRouteMessage(startCLPL:CLPlacemark,endCLPL:CLPlacemark) {
let request:MKDirectionsRequest = MKDirectionsRequest()
let startPL:MKPlacemark = MKPlacemark(placemark: startCLPL)
request.source = MKMapItem(placemark: startPL)
let endPL:MKPlacemark = MKPlacemark(placemark: endCLPL)
request.destination = MKMapItem(placemark: endPL)
let direction:MKDirections = MKDirections(request: request)
direction.calculate { (response:MKDirectionsResponse?, error:Error?) in
if error == nil {
for route in response!.routes {
print(route.name)
print(route.distance)
print(route.expectedTravelTime)
print(route.transportType)
print(route.polyline)
// 添加覆盖层数据模型
// 当我们添加一个覆盖层数据模型时, 系统绘自动查找对应的代理方法, 找到对应的覆盖层"视图"
self.mapView.add(route.polyline)
for step in route.steps {
print(step.instructions)
print(step.distance)
}
}
//MKDirectionsResponse
//routes: [MKRoute]
// MKRoute
// name: 路线名称
// advisoryNotices: [String] : 提示信息
// distance: CLLocationDistance 长度
// expectedTravelTime: NSTimeInterval: 预计到达时间段
// transportType : 行走方式(步行, 驾驶, 公交)
// polyline: MKPolyline: 导航路线对应的数据模型
// steps: [MKRouteStep]: 每一步该怎么走
// MKRouteStep
// instructions: String : 行走提示: 前方路口左转
// notice: 警告信息
// distance : 每一节路线的长度距离
// transportType: 每一路的交通方式
}
}
}
}
extension ViewController: MKMapViewDelegate {
/**
当添加一个覆盖层数据模型到地图上时, 地图会调用这个方法, 查找对应的覆盖层"视图"(渲染图层)
- parameter mapView: ditu
- parameter overlay: 覆盖层"数据模型"
- returns: 覆盖层视图
*/
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
var resultRender = MKOverlayRenderer()
if overlay.isKind(of: MKPolyline.self) {
// 不同的覆盖层数据模型, 对应不同的覆盖层视图来显示
let lineRender: MKPolylineRenderer = MKPolylineRenderer(overlay: overlay)
// 设置线宽
lineRender.lineWidth = 6
// 设置颜色
lineRender.strokeColor = UIColor.red
resultRender = lineRender
}
if overlay.isKind(of: MKCircle.self) {
let circleRender: MKCircleRenderer = MKCircleRenderer(overlay: overlay)
circleRender.fillColor = UIColor.cyan
circleRender.alpha = 0.5
resultRender = circleRender
}
return resultRender
}
}
3D视图
- 类似于地图街景,增强用户体验
let center = CLLocationCoordinate2DMake(23.132931, 113.375924)
let camera = MKMapCamera(lookingAtCenter: center, fromEyeCoordinate: CLLocationCoordinate2DMake(center.latitude, center.longitude + 0.001), eyeAltitude: 1)
mapView.camera = camera
- 地图截图
// 截图附加选项
let options = MKMapSnapshotOptions()
// 设置截图区域(在地图上的区域,作用在地图)
options.region = mapView.region
// 设置截图后的图片大小(作用在输出图像)
options.size = mapView.frame.size
// 设置截图后的图片比例(默认是屏幕比例, 作用在输出图像)
options.scale = UIScreen.main.scale
// 创建截图对象, 并开始截图
let snapshotter = MKMapSnapshotter.init(options: options)
snapshotter.start { (snapshot:MKMapSnapshot?, error:Error?) in
print(snapshot!)
}
- POI检索
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = "酒店"
request.region = mapView.region
let searcher: MKLocalSearch = MKLocalSearch(request: request)
searcher.start { (response:MKLocalSearchResponse?, error:Error?) in
print(error)
guard error != nil else {
return
}
guard let items = response?.mapItems else {
return
}
for item in items {
print(item.name!, item.phoneNumber!, item.url!)
}
}