3

I have a MapView displaying some annotations with displayPriority = .defaultHight to allow automatic clustering.

The MapView also displays the current user location which has a default display priority of required.

This causes my annotations to be hidden by the user location annotation when they are very close together.

I want to change this behavior by setting the display priority of the user location annotation to defaultLow.

I tried using this approach:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
        let userView = mapView.view(for: annotation)
        userView?.displayPriority = .defaultLow
        return userView
    }
    return mapView.view(for: annotation)
}

However userView is always nil and therefore my displayPriority modification is not applied.

Any ideas how the displayPriority of the MKUserLocation annotation view can be changed?

funkenstrahlen
  • 3,032
  • 2
  • 28
  • 40

2 Answers2

1

I spent hours trying to solve this problem by customizing the default user location annotation, but to no avail.

Instead, as a workaround, I made my own location marker and hid the default location annotation. Here's my code:

Add an annotaion variable to your viewController:

private var userLocation: MKPointAnnotation?

In your viewDidLoad, hide the default location marker:

mapView.showsUserLocation = false

Update the location in didUpdateLocations:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let userLocation = locations.first else { return }
        if self.userLocation == nil {
            let location = MKPointAnnotation()
            location.title = "My Location"
            location.coordinate = userLocation.coordinate
            mapView.addAnnotation(location)
            self.userLocation = location
        } else {
            self.userLocation?.coordinate = userLocation.coordinate
        }
    }

Then customize the annotation view in viewFor annotation:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            // user location annotation
            let identifier = "userLocation"
            var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)

            if annotationView == nil {
                annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
                (annotationView as? MKMarkerAnnotationView)?.markerTintColor = .blue
                annotationView?.canShowCallout = true
            } else {
                annotationView?.annotation = annotation
            }
            annotationView?.displayPriority = .defaultLow
            return annotationView
}

I changed the annotation's displayPriority to .defaultLow to make sure it won't hide other annotations.

Let me know if this helps!

JingWei Li
  • 11
  • 3
0

In case anyone is still struggling with this, you can do this using func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]):

// MARK: - MKMapViewDelegate

func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
    for view in views {
        if view.annotation is MKUserLocation {
            view.displayPriority = .defaultLow
            break
        }
    }
}

This way you can still use the system provided view for MKUserLocation without having to construct your own manually.

iMinichrispy
  • 134
  • 2
  • 14