SwiftUI Polyline not updating to follow user as they move

721 Views Asked by At

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 :) **

Showing the polyline stops updating 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
        
    }
    
    
}
0

There are 0 best solutions below