导航

导航-简介

  • 概念

    简单来说, 就是根据用户指定的位置, 进行路线规划; 然后根据用户在行走过程中, 实时的给出指引提示

  • 导航的三种实现方案

    1. 可以将需要导航的位置丢给系统的地图APP进行导航
    2. 发送网络请求到公司服务器获取导航数据, 然后自己手动绘制导航
    3. 利用三方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!)
    }
}

results matching ""

    No results matching ""