1
votes

I'm using iOS Mapbox SDK in my app. I changed image for an annotation to a custom image (It looks like a map marker). When I add an annotation to a specific coordinate on the map view, It will be added but the center of my custom annotation image (the marker) will be set on the coordinate. I need to change the marker position to set the bottom of the marker on the coordinate. I found a way but I do not know is there a better way or not? I converted the coordinate to a point, then changed the point y position, then converted the point to a new coordinate.

func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
    let reuseIdentifier = "annotationImage"
    var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: reuseIdentifier)

    if annotationImage == nil {
        annotationImage = MGLAnnotationImage(image: UIImage(named: "Orange")!, reuseIdentifier: reuseIdentifier)
    }
    return annotationImage
}

func addDestinationMarker(coordinate: CLLocationCoordinate2D) {
    guard let mapView = mapView else { return }
    if let annotations = mapView.annotations {
        mapView.removeAnnotations(annotations)
    }
    var point = mapView.convert(coordinate, toPointTo: mapView)
    point.y -= markerImageView.frame.height / 2
    let newCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
    let annotation = MGLPointAnnotation()
    annotation.coordinate = newCoordinate
    mapView.addAnnotation(annotation)
}
3

3 Answers

0
votes

I've run into this same issue and started to think that round map pins were becoming the defacto standard so they could just be plonked onto the map with the image centre denoting the coordinate. However if you take a look at this example on the Mapbox website, they use a non-round image and solve the offset problem quite nicely.

// The anchor point of an annotation is currently always the center. To
// shift the anchor point to the bottom of the annotation, the image
// asset includes transparent bottom padding equal to the original image
// height.
//
// To make this padding non-interactive, we create another image object
// with a custom alignment rect that excludes the padding.

image = image.withAlignmentRectInsets(UIEdgeInsets(top: 0, left: 0, bottom: image.size.height/2, right: 0))

This does mean that you need to generate pin images that are twice as tall, with the lower half transparent, but that's really not a big deal.

0
votes

You can solve this by leveraging the centerOffset property that MGLAnnotationView provides. Though I'm not sure if it's present in the MGLAnnotationImage you're using.

To set the anchor to the bottom of the annotation, use:

centerOffset.dy = -height / 2

If you set the frame beforehand, the height is simply frame.height.

0
votes

The other answers express things correctly but both are missing the correct syntax:

annotationView?.centerOffset.y = -(annotationView?.frame.height ?? 0) / 2

This will achieve the expected result.