I have spent a lot of time researching this question and have tried a few approaches but none have worked for me. Any help would be greatly appreciated by this Swift noob.
To gain more MapKit experience, I am trying to show the user their path with a polyline on the map that follows their movements, similar to run apps that track the user. I can track the user just fine but I cannot show a live map with a Polyline that updates as they move. When closing the map and coming back to it the polyline is updated with the missing coordinates. ** I suspect the answer to my problem relates to this :) **
Image showing the map after it loads and the user moves away from the Polyline. Closing the map and reopening redraws the missing points of the polyline
LocationViewModel.swift
var locationArray: [CLLocation] = []
var coordArray: [CLLocationCoordinate2D] = []
(...)
var coordinates2D:[CLLocationCoordinate2D] {
var coordArray = [CLLocationCoordinate2D]()
for c in locationArray {
let lat = c.coordinate.latitude
let long = c.coordinate.longitude
let x = CLLocationCoordinate2D(latitude: lat, longitude: long)
coordArray.append(x)
}
return coordArray
}
(...)
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for newLocation in locations {
let howRecent = newLocation.timestamp.timeIntervalSinceNow
guard newLocation.horizontalAccuracy < 20 && abs(howRecent) < 10 else { continue }
speeds.append(contentsOf: locationArray.map{$0.speed}) //append all new speed updates to the array
altitude.append(contentsOf: locationArray.map{$0.altitude}) //append all new speed updates to the array
locationArray.append(newLocation)
}
SecondMap.swift
import Foundation
import SwiftUI
import MapKit
struct SecondMap: UIViewRepresentable {
typealias UIViewType = MKMapView
@EnvironmentObject var model: LocationsModel
@State var regionZoom = LocationService.sharedLocInstance.locationManager.location?.coordinate
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.showsUserLocation = true
mapView.userTrackingMode = .followWithHeading
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
// uiView.removeAnnotation(uiView.annotations)
// uiView.showAnnotations(self.locations, animated: true)
if regionZoom != nil {
let span = MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005)
let region = MKCoordinateRegion(center: regionZoom!, span: span)
uiView.setRegion(region, animated: true)
}
let polyline = MKPolyline(coordinates: model.coordinates2D, count: model.coordinates2D.count)
uiView.removeOverlay(polyline)
uiView.addOverlay(polyline)
uiView.delegate = context.coordinator
}
static func dismantleUIView(_ uiView: MKMapView, coordinator: ()) {
// uiView.removeAnnotation(uiView.annotations)
}
//MARK: - Create Coordinator Class
func makeCoordinator() -> Coordinator {
return Coordinator()
}
class Coordinator: NSObject, MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// If the annotation is the user dot then return nil
if annotation is MKUserLocation {
return nil
}
// Create an annotation view
let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "business")
annotationView.canShowCallout = false
annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView.isHidden = true
return annotationView
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let routePolyline = overlay as? MKPolyline {
let renderer = MKPolylineRenderer(polyline: routePolyline)
renderer.strokeColor = UIColor.blue
renderer.lineWidth = 7
return renderer
}
return MKOverlayRenderer()
}
}
}
TrackerDetailCard
import SwiftUI
import MapKit
struct TrackerDetailView: View {
@EnvironmentObject var model: LocationsModel
@State var isMapShowing = false
// @State var regionZoom = LocationService.sharedLocInstance.locationManager.location?.coordinate
var body: some View {
NavigationView {
if !isMapShowing {
VStack(alignment: .leading) {
HStack{
Text("Map info and stuff")
Button {
self.isMapShowing = true
} label: {
Text("Launch Map")
.font(.system(size: 12))
.foregroundColor(.gray)
}
.buttonStyle(NEUMORPHISM_BUTTON())
} // HSTACK END
HStack {
Button {
LocationService.sharedLocInstance.locationManager.startUpdatingLocation()
} label: {
Text("Record runs")
.font(.system(size: 12))
.foregroundColor(.gray)
}
.buttonStyle(NEUMORPHISM_BUTTON_SQ())
Button {
LocationService.sharedLocInstance.locationManager.stopUpdatingLocation()
} label: {
Text("End recording")
.font(.system(size: 12))
.foregroundColor(.gray)
}
.buttonStyle(NEUMORPHISM_BUTTON_SQ())
Button {
print("button tapped")
} label: {
Text("Something")
.font(.system(size: 12))
.foregroundColor(.gray)
}
.buttonStyle(NEUMORPHISM_BUTTON_SQ())
}
VStack{
Text("Average Speed: \(model.avgSpeed)")
Text("Top Speed: \(model.topSpeed)")
// Text("Top Speed: \(model.altitude)")
}
Spacer()
} // VSTACK END
.navigationBarHidden(true)
}
else{
ZStack(alignment: .top){
// show map
SecondMap()
.ignoresSafeArea()
ZStack{
Rectangle()
.foregroundColor(.white)
.cornerRadius(5)
.frame(height: 48)
HStack{
Image(systemName: "location")
Spacer()
Button("Back to home") {
self.isMapShowing = false
}
}.padding()
}.padding()
}
}
} // BODY END
}
}