绘制跟随用户当前位置的 MKPolyline
Drawing MKPolyline Which Follows User's Current Location
我正在尝试在用户移动时在他们身后画一条路径,跟踪他们的路径(就像 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()
}
}
}
谢谢!
问题是您正在抓取一个位置,将其添加到数组中,然后从数组中的最后一个位置 allLocations[allLocations.count - 1]
(现在是当前位置)创建一条折线到当前位置(即自身)。
因此,在向数组添加新位置之前,从数组中获取最后一项 previousCoordinate
:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let currentLocation = locations.first(where: { [=10=].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)
}
正如您在上面看到的,我还建议检查位置更新的水平精度,以确保它是非负的。
无论如何,这会产生:
其他一些观察结果:
我建议在 viewDidLoad
中停用 noLocation
模式。我的上述模式不需要数组中的虚拟值。
另一个问题是,在 didChangeAuthorization
中,您正在实例化一个新的 CLLocationManager
而不是设置其属性。因此,您将丢失 viewDidLoad
中原始 CLLocationManager
的配置。没有必要再实例化一个,但是如果你这样做了,记得正确配置它。
我正在尝试在用户移动时在他们身后画一条路径,跟踪他们的路径(就像 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()
}
}
}
谢谢!
问题是您正在抓取一个位置,将其添加到数组中,然后从数组中的最后一个位置 allLocations[allLocations.count - 1]
(现在是当前位置)创建一条折线到当前位置(即自身)。
因此,在向数组添加新位置之前,从数组中获取最后一项 previousCoordinate
:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let currentLocation = locations.first(where: { [=10=].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)
}
正如您在上面看到的,我还建议检查位置更新的水平精度,以确保它是非负的。
无论如何,这会产生:
其他一些观察结果:
我建议在
viewDidLoad
中停用noLocation
模式。我的上述模式不需要数组中的虚拟值。另一个问题是,在
didChangeAuthorization
中,您正在实例化一个新的CLLocationManager
而不是设置其属性。因此,您将丢失viewDidLoad
中原始CLLocationManager
的配置。没有必要再实例化一个,但是如果你这样做了,记得正确配置它。