Transferring Coordinates to a MapView with Pin

Viewed 194

I am trying to display a map pin on a map. Upon entry of a transaction the details are saved along with the location coordinates. In a list of transaction entries, the user may click on an entry for more detail information including a small map showing the transaction location.

Based on Asperi's suggestions at adding a MapMarker to MapKit in swiftUI 2 it appears that I need to declare an identifiable structure in order to use a map pin.

In the DetailView the latitude and longitude are copied to a coordinate parameter before transmission to MapView.

struct DetailView: View {
       
    var coordinate: CLLocationCoordinate2D {
          CLLocationCoordinate2D(
          latitude: item.entryLat,
          longitude: item.entryLong)
     }
        
        var body: some View {
            
            VStack {
                MapView(coordinate: coordinate)
                    .ignoresSafeArea(edges: .all)
                    .frame(height: 400)
                    .padding(.vertical, 10)
            }
       }
  }

MapView is where I'm having trouble. I'm not sure how to pass in my coordinates for the region and the marker (xxxxx). Copying` coordinate to the @State region and the marker produces the error "Argument passed to call that takes no arguments".

struct Marker: Identifiable {
 let id = UUID()
 var location: MapMarker
}


struct MapView: View {
    
    var coordinate: CLLocationCoordinate2D
    
    @State private var region = MKCoordinateRegion(center:    CLLocationCoordinate2D(xxxxxxx), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
    
    let markers = [Marker(location: MapMarker(coordinate: CLLocationCoordinate2D(xxxxxxx), tint: .red))]
    
    var body: some View {
        
            Map(coordinateRegion: $region, showsUserLocation: true,
              annotationItems: markers) { marker in
                marker.location
            }.edgesIgnoringSafeArea(.all)
    }
}
1 Answers

Sounds like for your application, declaring the region as a constant will work. The code would look like this:

struct Marker: Identifiable {
    let id = UUID()
    var location: MapMarker
}

struct MapView: View {
    var coordinate: CLLocationCoordinate2D
    
    var body: some View {
        
        Map(coordinateRegion: .constant(MKCoordinateRegion(center: coordinate,
                                                           span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))),
            showsUserLocation: true,
            annotationItems: [Marker(location: MapMarker(coordinate: coordinate))]) { marker in
                marker.location
        }.edgesIgnoringSafeArea(.all)
    }
}

If you still wanted to use it as a @State variable, you could use a custom init to set the value:

struct MapView: View {
    var coordinate: CLLocationCoordinate2D
    
    @State private var region : MKCoordinateRegion
    
    init(coordinate : CLLocationCoordinate2D) {
        self.coordinate = coordinate
        _region = State(initialValue: MKCoordinateRegion(center: coordinate,
                                                             span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)))
    }
    
    var body: some View {
        Map(coordinateRegion: $region,
            showsUserLocation: true,
            annotationItems: [Marker(location: MapMarker(coordinate: coordinate))]) { marker in
                marker.location
        }
        .edgesIgnoringSafeArea(.all)
    }
}

Lastly, I'm defining the markers array inline, but you could split it out into a computed property:


    var markers : [Marker] {
        [Marker(location: MapMarker(coordinate: coordinate))]
    }
    
    var body: some View {
        Map(coordinateRegion: $region,
            showsUserLocation: true,
            annotationItems: markers) { marker in
                marker.location
        }
        .edgesIgnoringSafeArea(.all)
    }
Related