绘制跟随用户当前位置的MKPolyline

时间:2020-07-24 02:40:29

标签: ios swift mapkit mkpolyline

我正在尝试在用户移动时在其后面绘制一条路径,以跟踪其路径(就像用户开始锻炼时Strava或FitBit应用程序所做的那样)。到目前为止,地图以用户的位置为中心,但在用户移动时并未开始绘制。我尝试使用renderForOverlay实现此功能,但在测试时却无法实现。代码如下:

ViewController.swift

import UIKit
import MapKit
import CoreLocation

class StartWorkoutViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {

    @IBOutlet weak var mapsView: MKMapView!
    @IBOutlet weak var startButton: UIButton!
    
    var locationManager: CLLocationManager!
    var allLocations: [CLLocation] = []
    
    @IBAction func startButton(_ sender: Any) {
        // Start the workout
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Request user's current location
        locationManager = CLLocationManager()
        locationManager?.requestAlwaysAuthorization()
        locationManager?.desiredAccuracy = kCLLocationAccuracyBest
        locationManager?.startUpdatingLocation()
        locationManager?.startUpdatingHeading()
        locationManager?.delegate = self
        
        mapsView?.showsUserLocation = true
        mapsView?.mapType = MKMapType(rawValue: 0)!
        mapsView?.userTrackingMode = .follow
        mapsView?.delegate = self
        
        let noLocation = CLLocationCoordinate2D()
        let viewRegion = MKCoordinateRegion(center: noLocation, latitudinalMeters: 100, longitudinalMeters: 100)
        mapsView?.setRegion(viewRegion, animated: true)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // Add location to the array and prepare to draw a line between last location and current location
        print("Location Updated")
        allLocations.append(locations[0])
        
        let previousLocation = allLocations[allLocations.count - 1]
        let newLocation = locations[0]
        
        let previousCoordinates = previousLocation.coordinate
        let newCoordinates = newLocation.coordinate
        
        var area = [previousCoordinates, newCoordinates]
        let polyline = MKPolyline(coordinates: &area, count: area.count)
        mapsView.addOverlay(polyline)
    }
    
// DOES NOT WORK
    func mapView(_ mapsView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if overlay is MKPolyline {
            let polylineRenderer = MKPolylineRenderer(overlay: overlay)
            polylineRenderer.strokeColor = UIColor.red
            polylineRenderer.lineWidth = 4
            return polylineRenderer
        } else {
            return MKPolylineRenderer()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        // If the authorisation for the user's location has changed, ask again
        if status != .authorizedAlways {
            locationManager = CLLocationManager()
            locationManager?.requestAlwaysAuthorization()
        }
    }
}

谢谢!

1 个答案:

答案 0 :(得分:1)

问题是您要获取一个位置,将其添加到数组中,然后从数组的最后一个位置allLocations[allLocations.count - 1](现在是当前位置)到当前位置创建一条折线位置(即本身)。

因此,在将新位置添加到数组之前,从数组中获取最后一项previousCoordinate

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let currentLocation = locations.first(where: { $0.horizontalAccuracy >= 0 }) else {
        return
    }

    let previousCoordinate = allLocations.last?.coordinate
    allLocations.append(currentLocation)

    if previousCoordinate == nil { return }

    var area = [previousCoordinate!, currentLocation.coordinate]
    let polyline = MKPolyline(coordinates: &area, count: area.count)
    mapsView.addOverlay(polyline)
}

我还建议,如您在上面看到的那样,检查位置更新的水平精度,以确保它不是负值。

反正会产生:

enter image description here


其他一些观察结果:

  1. 我建议停用noLocation中的viewDidLoad模式。我上面的模式不需要数组中的虚拟值。

  2. 另一个问题是,在didChangeAuthorization中,您将实例化一个新的CLLocationManager而不设置其属性。因此,您将丢失CLLocationManager中原始viewDidLoad的配置。无需实例化另一个实例,但是如果要实例化,请记住正确配置它。