How to fix custom Point Annotations from disappearing from overlap?
Asked Answered
D

1

2

Attempting to show custom point annotations from MapKits local search. When the annotations first load on the map all of them show, but then the overlapping ones disappear. And they only reappear when you zoom in on the area.

Many stack solutions have stated to user view?.displayPriority = .required. But for some reason this line of code doesn't work.

Local Search Function on button press

@IBAction func groceryLocalSearch(_ sender: Any) {
    self.localStoresArray.removeAll()
    self.LocalMapKit.removeAnnotations(self.LocalMapKit.annotations)
    currentLocationBtn.isHidden = false
    localRequest.naturalLanguageQuery = "Grocery"
    //localRequest.region = LocalMapKit.region

    self.localSearchBtn.isEnabled = false

    let search = MKLocalSearch(request: localRequest)

    search.start(completionHandler: {(response, error) in

        if error != nil{
            print("Error occured when searching: \(error!.localizedDescription)")
        } else if response!.mapItems.count == 0 {
            print("There were no results in the search")
        } else {
            print("\(response!.mapItems.count) Results found!")
            for item in response!.mapItems {
                //Add each item to a array to access in table view
                self.localStoresArray.append(item)
                let stores = MKPointAnnotation()
                stores.title = item.name
                stores.coordinate = item.placemark.coordinate
                self.LocalMapKit.addAnnotation(stores)
            }
        }
        self.LocalMapKit.showAnnotations(self.LocalMapKit.annotations, animated: true)
        self.localStoresTableView.reloadData()
    })

View for annotation func

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?{
    guard annotation is MKPointAnnotation else { return nil }

    let identifier = "Annotation"

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)

    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.displayPriority = .required
        //annotationView?.canShowCallout = true
    } else {
        annotationView!.annotation = annotation

    }

    return annotationView
}

I want it so that when the user does the local search it shows all annotations not matter if they are close to each other without having to zoom in.

Image of current map view:

imgur.com/a/4if6fdY

Dominic answered 23/4, 2019 at 21:31 Comment(0)
T
4

You apparently haven’t set the delegate for your map view because those annotation views are not MKPinAnnotationView, but rather the default MKMarkerAnnotationView. If you’re going to implement MKMapViewDelegate methods, you have to set the delegate of the map view (either in IB or programmatically).

This disappearing act is because the default MKMarkerAnnotationView is configured to enable clustering but you haven’t registered a MKMapViewDefaultClusterAnnotationViewReuseIdentifier.

So, if you really want pin annotation views and you don’t want clustering, set your map view’s delegate and your method should accomplish what you want.


I’d personally suggest you reduce view controller bloat by moving the configuration of your annotation view into a MKPinAnnotationView subclass:

class CustomAnnotationView: MKPinAnnotationView { // or use `MKMarkerAnnotationView` if you want
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        displayPriority = .required
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Then, if you’re targeting iOS 11 and later, in your viewDidLoad, you can register your class, and you don’t have to implement mapView(_:viewFor:) at all:

mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)

Or, if you want to enjoy clustering properly, you can expand your CustomAnnotationView:

class CustomAnnotationView: MKPinAnnotationView { // or use `MKMarkerAnnotationView` if you want
    static let preferredClusteringIdentifier: String? = Bundle.main.bundleIdentifier! + ".CustomAnnotationView"

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        clusteringIdentifier = CustomAnnotationView.preferredClusteringIdentifier
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var annotation: MKAnnotation? {
        didSet {
            clusteringIdentifier = CustomAnnotationView.preferredClusteringIdentifier
        }
    }
}

And then register both your annotation view and a cluster annotation view:

mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)

Then you enjoy clustering with minimal effort.

Tilth answered 23/4, 2019 at 22:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.