swiftswiftuimapkitmapkitannotation

How do you properly display custom pins in SwiftUI / Mapkit?


I am in the process of building a SwiftUI app that relies on MapKit.

But I am encountering an issue with the rendering of the custom pin marker.

Whenever I add the pin, this is rendered from the center of the image so it does not properly align with the current location.

I have tried adding offsets, changing the origin, but the custom pin image basically goes out of bounds.

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    let view = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
    let size = CGSize(width: 35, height: 40)
    UIGraphicsBeginImageContext(size)
    UIImage(named: "customPin")?.draw(in: CGRect(origin: CGPoint(x: 0, y: 20), size: size))
    
    //let context = UIGraphicsGetCurrentContext()!
    //context.move(to: CGPoint(x:0, y: -200))
    // This code didn't affect the rendering
    
    view.image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    view.canShowCallout = true
    return view
}

Basically what I think is happening is that the offsets that I am applying are moving the image but the bounds of the CGRect remain in the same spot. I do not know how to offset both.


Solution

  • In Apple’s docs: Annotating a Map with Custom Data they provide the following sample code:

    private func setupSanFranciscoAnnotationView(for annotation: SanFranciscoAnnotation, on mapView: MKMapView) -> MKAnnotationView {
       let reuseIdentifier = NSStringFromClass(SanFranciscoAnnotation.self)
       let flagAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier, for: annotation)
    
       flagAnnotationView.canShowCallout = true
    
       // Provide the annotation view's image.
       let image = #imageLiteral(resourceName: "flag")
       flagAnnotationView.image = image
    
       // Provide the left image icon for the annotation.
       flagAnnotationView.leftCalloutAccessoryView = UIImageView(image: #imageLiteral(resourceName: "sf_icon"))
    
       // Offset the flag annotation so that the flag pole rests on the map coordinate.
       let offset = CGPoint(x: image.size.width / 2, y: -(image.size.height / 2) )
       flagAnnotationView.centerOffset = offset
        
       return flagAnnotationView
    }
    

    They’re using the centerOffset to reposition the image/annotation. Have you tried this? They have shifted the image up and also to the right as they want to align a corner to the coordinate, usually I just want center-bottom aligned so supply zero for the x offset.