Search code examples
xcodeswiftuimapkitwrappermapkitannotation

Customise Annotation in MapKit in swiftUI


Im try to customise my annotation in MapKit and SwiftUI

From the code below, I search in the map the specific coordinate (coord) and I display with my custom annotation.

1) I'm try to increase the size of the UIimage because to small (see the picture attached)and change the color, any idea how?

2)in the map after the app start it display only the icon, after I tap on the icon the annotation appear, any idea how to display immediately my annotation without tapping?

3)now in the annotation I manage to display title and subtitle, how to display also the coordinate

struct MapView: UIViewRepresentable {

    let Mm : MapManager
    let coord = CLLocationCoordinate2D(latitude: 52.28792, longitude: 4.73415327)

    class Coordinator: NSObject, MKMapViewDelegate {
        var parent : MapView

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

        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "TESTING NOTE")
            annotationView.canShowCallout = true
            annotationView.image = UIImage(systemName: "location.circle")

            return annotationView
        }


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

    func makeUIView(context: Context) -> MKMapView {

    let view =  MKMapView(frame: .zero)
        Mm.georeverseCoordinate(coord) { (pin) in

                if let pinOK = pin {

                    view.removeAnnotation(pinOK)
                    view.mapType = MKMapType.satellite
                    let span = MKCoordinateSpan(latitudeDelta: 0.04, longitudeDelta: 0.04)
                    let region = MKCoordinateRegion(center: self.coord, span: span)
                    view.setRegion(region, animated: true)
                    view.delegate = context.coordinator
                    view.addAnnotation(pinOK)
                }

            }
        return view
    }

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

    }

}

Map manager

class MapManager: NSObject, CLLocationManagerDelegate {

    static let shared = MapManager()




    func georeverseCoordinate(_ coord: CLLocationCoordinate2D , closure:  @escaping (Pin?) -> Void) {

        let location = CLLocation(latitude: coord.latitude, longitude: coord.longitude)


        let geocoder = CLGeocoder()

        geocoder.reverseGeocodeLocation(location) { (arrayResponse, error) in
            if let errorTest = error {
                debugPrint(errorTest.localizedDescription)
                closure(nil)
                return
            }

            if let arrayPins = arrayResponse {

                if let valorePinArray = arrayPins.first {

                    debugPrint(valorePinArray.locality!)
                    debugPrint(valorePinArray.isoCountryCode!)

                    let pin = Pin(title: valorePinArray.locality!, subtitle: valorePinArray.isoCountryCode!, coordinate: valorePinArray.location!.coordinate)

                    closure(pin)

                }
                else { closure(nil) }
            }
            else { closure(nil) }
        }
    }
}

Pin Model

class Pin:NSObject, MKAnnotation {

    var title : String?
    var subtitle : String?
    var coordinate : CLLocationCoordinate2D
    var color: UIColor?

    init(title: String?, subtitle: String?, coordinate: CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }


}

Image to small


Solution

  • 1) - There seems to be a bug that makes it difficult to change the colour of SF Symbols with tintColor and a specific rendering mode but there is a workaround that also allows an easy way to change the size of the symbol.

    In mapView:viewFor annotation add the following:

    annotationView.canShowCallout = true    
    annotationView.image = UIImage(systemName: "location.circle")?.withTintColor(.systemGreen, renderingMode: .alwaysOriginal)
    let size = CGSize(width: 40, height: 40)
    annotationView.image = UIGraphicsImageRenderer(size:size).image {
         _ in annotationView.image!.draw(in:CGRect(origin:.zero, size:size))
    }
    

    2) - To show the callout as soon as the annotation is added to the map, use selectAnnotation.

    view.addAnnotation(pinOK)
    view.selectAnnotation(pinOK, animated: true)
    

    3) - The coordinate is available when your annotation is being constructed so you can simply change the init in the Pin class:

    init(title: String?, subtitle: String?, coordinate: CLLocationCoordinate2D) {
        self.coordinate = coordinate
        self.title = "\(coordinate.latitude) : \(coordinate.longitude)"
        self.subtitle = subtitle
    }