Adding multiple annotations to map with polygons using swiftui

Viewed 31

I am using SwiftUI and UIViewRepresentable to display a map with different coloured MKPolygons as well as MKAnnotations.

While I can get the polygons to render correctly, I cannot get more than one annotation to load at a time. I think it has something to do with the way I am calculating the value of 'landmarks' as it's only reading a single line of the data array, but having trouble figuring out another way to calculate this.

I intend to add more polygons and annotations so looking for a scaleable solution and hoping my current approach is somewhat in the right direction.

My code as follows: (I'm a beginner so apologies if the approach I'm taking is ugly!)


import SwiftUI
import MapKit

fileprivate class BlueSector: MKPolygon {
}

fileprivate class RedSector: MKPolygon {
}

fileprivate class MapPins: NSObject, MKAnnotation {
    let title: String?
    let subtitle: String?
    let coordinate: CLLocationCoordinate2D
    
    init(title: String?,
         subtitle: String?,
         coordinate: CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
}

struct MapView: UIViewRepresentable {

    let region: MKCoordinateRegion
    let todCoordinates: [CLLocationCoordinate2D]
    let oplCoordinates: [CLLocationCoordinate2D]
    let mapPoints: [(title: String, subtitle: String, coordinate: CLLocationCoordinate2D)]

  func makeUIView(context: Context) -> MKMapView {
      
      let mapView = MKMapView()
      mapView.delegate = context.coordinator
      mapView.region = region

      let todpolygon = BlueSector(coordinates: todCoordinates, count: todCoordinates.count)
      mapView.addOverlay(todpolygon)
      
      let oplpolygon = RedSector(coordinates: oplCoordinates, count: oplCoordinates.count)
      mapView.addOverlay(oplpolygon)
      
      let landmarks = MapPins(title: mapPoints[0].0, subtitle: mapPoints[0].1, coordinate: mapPoints[0].2)
      mapView.addAnnotation(landmarks)
              
    return mapView
  }

  func updateUIView(_ view: MKMapView, context: Context) {}

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }
}


class Coordinator: NSObject, MKMapViewDelegate {
  var parent: MapView

  init(_ parent: MapView) {
    self.parent = parent
  }

  func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if let routePolyline = overlay as? MKPolygon {
        let renderer = MKPolygonRenderer(overlay: routePolyline)
        if overlay is BlueSector {
            renderer.strokeColor = UIColor.systemBlue
            renderer.lineWidth = 2
            renderer.fillColor = UIColor.systemCyan
            renderer.alpha = 0.5
        } else {
            renderer.strokeColor = UIColor.systemRed
            renderer.lineWidth = 2
            renderer.fillColor = UIColor.systemPink
            renderer.alpha = 0.5
        }
      return renderer
    }
      
    return MKOverlayRenderer()
  }
    
    func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

        let identifier = "pinAnnotation"
        var annotationView = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView

        if annotationView == nil {
            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView?.canShowCallout = true
        }

        annotationView?.annotation = annotation
        return annotationView
    }
}


struct ContentView: View {
  @State private var region = MKCoordinateRegion(
    center: CLLocationCoordinate2D(latitude: -24.1500, longitude: 133.2500),
    span: MKCoordinateSpan(latitudeDelta: 50, longitudeDelta: 50)
  )

// BLUE POLYGON COORDINATES
  @State private var todCoordinates = [
        CLLocationCoordinate2D(latitude: -23.1902, longitude: 127.0806),
        CLLocationCoordinate2D(latitude: -24.2905, longitude: 128.0645),
        CLLocationCoordinate2D(latitude: -26.0708, longitude: 128.0648),
        CLLocationCoordinate2D(latitude: -28.4816, longitude: 130.4419),
        CLLocationCoordinate2D(latitude: -28.4826, longitude: 130.4852),
        CLLocationCoordinate2D(latitude: -28.1001, longitude: 131.3645),
        CLLocationCoordinate2D(latitude: -30.2052, longitude: 133.5951),
        CLLocationCoordinate2D(latitude: -29.0006, longitude: 136.4946),
        CLLocationCoordinate2D(latitude: -28.0017, longitude: 137.5943),
        CLLocationCoordinate2D(latitude: -26.1314, longitude: 138.2312),
        CLLocationCoordinate2D(latitude: -22.1747, longitude: 136.3819),
        CLLocationCoordinate2D(latitude: -21.5143, longitude: 136.2242),
        CLLocationCoordinate2D(latitude: -21.2947, longitude: 136.1949),
        CLLocationCoordinate2D(latitude: -21.1201, longitude: 131.5020),
        CLLocationCoordinate2D(latitude: -23.1304, longitude: 128.2753),
        CLLocationCoordinate2D(latitude: -23.1902, longitude: 127.0806),
  ];
    
 // RED POLYGON COORDINATES
    @State private var oplCoordinates = [
        CLLocationCoordinate2D(latitude: -30.2052, longitude: 133.5951),
        CLLocationCoordinate2D(latitude: -29.0006, longitude: 136.4946),
        CLLocationCoordinate2D(latitude: -28.0017, longitude: 137.5943),
        CLLocationCoordinate2D(latitude: -26.1314, longitude: 138.2312),
        CLLocationCoordinate2D(latitude: -28.5948, longitude: 143.3004),
        CLLocationCoordinate2D(latitude: -29.5342, longitude: 142.4100),
        CLLocationCoordinate2D(latitude: -31.0006, longitude: 142.4837),
        CLLocationCoordinate2D(latitude: -31.4744, longitude: 143.3102),
        CLLocationCoordinate2D(latitude: -33.0014, longitude: 143.3050),
        CLLocationCoordinate2D(latitude: -33.2030, longitude: 140.3420),
        CLLocationCoordinate2D(latitude: -33.0506, longitude: 140.1330),
        CLLocationCoordinate2D(latitude: -32.5153, longitude: 139.4819),
        CLLocationCoordinate2D(latitude: -31.3500, longitude: 138.5950),
        CLLocationCoordinate2D(latitude: -31.3456, longitude: 135.2446),
        CLLocationCoordinate2D(latitude: -30.2052, longitude: 133.5951),
    ];
 
// ANNOTATION DATA FOR BOTH POLYGONS
    @State private var mapPoints = [
        (title: "TOD",
         subtitle: "Tod",
         coordinate: CLLocationCoordinate2D(latitude: -23.6980, longitude: 133.8807)),
        (title: "OPL",
         subtitle: "Opal",
         coordinate: CLLocationCoordinate2D(latitude: -30.5929, longitude: 138.4039)),
         ];
    
  var body: some View {
      MapView(
      region: region,
      todCoordinates: todCoordinates,
      oplCoordinates: oplCoordinates,
      mapPoints: mapPoints
    )
      .edgesIgnoringSafeArea(.top)
      }
  }

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
1 Answers

You are currently adding only the first object from the array instead of that you just need to loop through your mapPoints array and add it as an annotation in MapView.

for pin in mapPoints {
    let landmarks = MapPins(title: pin.0, subtitle: pin.1, coordinate: pin.2)
    mapView.addAnnotation(landmarks)
}
//Or simply
let annotations = mapPoints.map({ MapPins(title: $0.0, subtitle: $1.1, coordinate: $2.2) })
mapView.addAnnotations(annotations)

Suggestion:- Instead of creating an array of tuples better to create an array of struct models to easily manage your location data.

struct LocationPoint {
    let title: String
    let subtitle: String
    let coordinate: CLLocationCoordinate2D
}
Related