mapbox-maps-ios icon indicating copy to clipboard operation
mapbox-maps-ios copied to clipboard

Updating the image of a PointAnnotation in response to a tap

Open jrbj opened this issue 3 years ago • 5 comments

New Feature

I'd like a way to change the image of an annotation (PointAnnotation) in response to a tap.

I've tried this in the AnnotationInteractionDelegate and it doesn't seem to work:

extension MapViewController: AnnotationInteractionDelegate {
  func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) {
    guard let tappedAnnotation = annotations.first else { return }
    DispatchQueue.main.async {
      if let pointAnnotationManager = self.pointAnnotationManager {
        if var annotation = pointAnnotationManager.annotations.first(where: { $0.id == tappedAnnotation.id }) {
          annotation.image = .init(image: UIImage(named: "orange")!, name: tappedAnnotation.id)
        }
      }
    }
  }
}

I've also tried removing the old annotation, creating a new one with a new image, and then adding it to the pointAnnotationManager.

Why

This would be used to show that a point of interest has been selected.

jrbj avatar Aug 11 '22 04:08 jrbj

I wasn't sure if it was a bug. If it is, I can refile with the bug template.

jrbj avatar Aug 11 '22 04:08 jrbj

deHighlight(completion: { [weak self] in guard let marker = marker as? MapBoxPointAnnotationUserData else { return } self?.vehiclePinsAnnotationManager?.annotations.removeAll(where: { annotation in if let userData = annotation.userInfo?["userData"] as? RiderMapMarkerItem { return userData.remoteID == data.remoteID }

    return false
  })

  self?.mapRenderer?.highlightMarker(marker: marker, completion: { [weak self] data in
    guard var pointAnnotation = (data as? MapBoxPointAnnotationUserData)?.pointAnnotation else { return }

    pointAnnotation.iconAnchor = .bottom
    pointAnnotation.iconOffset = [0, 10]
    self?.seletedPinsAnnotationManager?.annotations = [pointAnnotation]
  })
})

JenishKananiLime avatar Aug 11 '22 21:08 JenishKananiLime

Hi @jrbj, this is expected behavior as PointAnnotation is a value type(struct), modifying it creates a copy of the value.

This means that the annotation you assign a new image to, is a copy of the annotation managed by the annotation manager.

In order for this to work you'd need to associate the modified annotation back with its manager.

extension MapViewController: AnnotationInteractionDelegate {
    func annotationManager(_ manager: AnnotationManager, didDetectTappedAnnotations annotations: [Annotation]) {
        guard let tappedAnnotation = annotations.first else { return }
        DispatchQueue.main.async {
            if let pointAnnotationManager = self.pointAnnotationManager,
               let index = pointAnnotationManager.annotations.firstIndex(where: { $0.id == tappedAnnotation.id }) {

                var annotation = pointAnnotationManager.annotations[index]
                annotation.image = .init(image: UIImage(named: "orange")!, name: tappedAnnotation.id)
                pointAnnotationManager.annotations[index] = annotation
            }
        }
    }
}

evil159 avatar Aug 12 '22 11:08 evil159

Sorry, @evil159 I just tried implementing the code you provided, but the image of the annotation still doesn't update.

I can print the image property and see that the image has changed, but it's still not reflected on the map. Is there anything that needs to be done to force the map to re-render the annotations?

I've even tried creating a new PointAnnotation struct, removing the existing annotation, and appending the new point annotation.

jrbj avatar Aug 13 '22 06:08 jrbj

@evil159 @JenishKananiLime I figured it out. I was using the same name in the annotation.image and that seems like it was causing a cached representation to be fetched.

annotation.image = .init(image: UIImage(named: "orange")!, name: tappedAnnotation.id) In the original non-working code, I could change the UIImage to anything, but it would never change from what the original image was because I was always using the same tappedAnnotation.id. Once the changed the value I was passing into name to something more appropriate like "orange-image" it worked as expected.

Thanks again for your help. I am curious if this is a bug with the cache though?

jrbj avatar Aug 13 '22 07:08 jrbj

Any more insights regarding if this issue is related to the caching?

Patrick3131 avatar Oct 03 '22 16:10 Patrick3131

I'm finding this also doesn't work when removing an annotation manager and recreating a new one using a different ID.

mapTouchAnnotationManager?.annotations = []
mapView.annotations.removeAnnotationManager(withId: mapTouchAnnotationID)
mapTouchAnnotationManager = mapView.annotations.makePointAnnotationManager(id: annotation.id)
mapTouchAnnotationManager!.annotations = [annotation]

Above will still load in an image from the previous removed annotation manager.

Definitely a 🐞

jay-cohen avatar Oct 05 '22 14:10 jay-cohen

The issue with cached annotation images is addressed in this PR https://github.com/mapbox/mapbox-maps-ios/pull/1583, it will be released in version 10.9.0, currently available as pre-release 10.9.0-beta.2.

evil159 avatar Oct 05 '22 14:10 evil159

The issue with cached annotation images is addressed in this PR #1583, it will be released in version 10.9.0, currently available as pre-release 10.9.0-beta.2.

When can we expect 10.9.0 to finalise and does your PR require code changes?

jay-cohen avatar Oct 12 '22 14:10 jay-cohen