Mkmap iOS11 clusters doesn't split up after max zoom, how to set it up?
Asked Answered
B

2

10

First, my code is perfectly running. I have well set up and mapView.register my annotation markers and cluster.

When I zoom out the annotations fusion as expected in my cluster views, when I zoom in, same good result, except at a certain point. When too many annotations are too close from each other, the cluster view doesn't split up into my two annotation views anymore.

So I search a way to be able to setup this "zoom level" that will makes appear my two annotations even if there are really close from each other.

Here are my cluster views with a high zoom on the map: enter image description here

Here if I zoom at the maximum: Well, one of the cluster views split into two, but doesn't reveal the 4 annotations.
enter image description here

I also try to setup the displayPriority to be higher for my two annotations, than the cluster view, but the result is still the same. Any ideas ?

Blairblaire answered 19/10, 2017 at 10:0 Comment(1)
how did it go? same issue here.Metalinguistic
A
12

You will need to keep track of the zoom level of the map, and reload your annotations when you cross a zoom level that you specify.

private let maxZoomLevel = 9
private var previousZoomLevel: Int?
private var currentZoomLevel: Int?  {
    willSet {
        self.previousZoomLevel = self.currentZoomLevel
    }
    didSet {
        // if we have crossed the max zoom level, request a refresh
        // so that all annotations are redrawn with clustering enabled/disabled
        guard let currentZoomLevel = self.currentZoomLevel else { return }
        guard let previousZoomLevel = self.previousZoomLevel else { return }
        var refreshRequired = false
        if currentZoomLevel > self.maxZoomLevel && previousZoomLevel <= self.maxZoomLevel {
            refreshRequired = true
        }
        if currentZoomLevel <= self.maxZoomLevel && previousZoomLevel > self.maxZoomLevel {
            refreshRequired = true
        }
        if refreshRequired {
            // remove the annotations and re-add them, eg
            let annotations = self.mapView.annotations
            self.mapView.removeAnnotations(annotations)
            self.mapView.addAnnotations(annotations)
        }
    }
}

private var shouldCluster: Bool {
    if let zoomLevel = self.currentZoomLevel, zoomLevel <= maxZoomLevel {
        return false
    }
    return true
}

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    // https://mcmap.net/q/243196/-how-to-find-current-zoom-level-of-mkmapview
    let zoomWidth = mapView.visibleMapRect.size.width
    let zoomLevel = Int(log2(zoomWidth))
    self.currentZoomLevel = zoomLevel
}

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    // for me, annotation reuse doesn't work with clustering
    let annotationView = CustomAnnotationView(annotation: annotation)
    if self.shouldCluster {
        annotationView.clusteringIdentifier = "custom-id"
    } else {
        annotationView.clusteringIdentifier = nil
    }
    return annotationView
}
Aldredge answered 6/3, 2018 at 2:15 Comment(2)
thats it! save my day. Another problem is this; It even clusters for two items. I want to limit this. Don't cluster from 5 items. How can we do it?Conquest
But this will have the annotation view a flash effect when reload (remove and add), especially those after cluster still don't need to group.Photoflash
S
4

In my case, ! EVERY TIME ! I didn't update the clusteringIdentifier

in "func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation)"

When the MKAnnotationView is reused by the mapView.dequeueReusableAnnotationView(withIdentifier: "identifier", for: annotation), the clusteringIdentifier will be nil. (reset)

That's the reason why the clusters doesn't work.

AnnotationView.swift

import MapKit

// MARK: - Define
struct AnnotationViewInfo {
    static let identifier = "AnnotationView"
}


final class AnnotationView: MKAnnotationView {

// MARK: - Initializer
override init(annotation: MKAnnotation!, reuseIdentifier: String!) {
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    setView()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setView()
}

// MARK: - Value
// MARK: Public
override var annotation: MKAnnotation? {
    willSet { update(annotation: newValue) }
}



// MARK: - Function
// MARK: Private
private func setView() {
    if #available(iOS 11.0, *) {
        collisionMode        = .rectangle
        clusteringIdentifier = AnnotationViewInfo.identifier
    }

    canShowCallout = true
    image = #imageLiteral(resourceName: "pin01").resizedImage(size: CGSize(width: #imageLiteral(resourceName: "pin01").size.width/4.0, height: #imageLiteral(resourceName: "pin01").size.height/4.0), scale: 1.0)
}


private func update(annotation: MKAnnotation?) {
    if #available(iOS 11.0, *) {
        clusteringIdentifier = AnnotationViewInfo.identifier
    }

    // TODO: Update the annotationView

  }
}

MKMapViewDelegate

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if #available(iOS 11.0, *) {
    switch annotation {
    case is PointAnnotation:         return mapView.dequeueReusableAnnotationView(withIdentifier: AnnotationView1Info.identifier,       for: annotation)
    case is MKClusterAnnotation:     return mapView.dequeueReusableAnnotationView(withIdentifier: ClusterAnnotationViewInfo.identifier, for: annotation)
    case is MKUserLocation:          return nil
    default:                         return nil
    }

   } else {
      return nil
   }
}

Key Point (You must update the "clusteringIdentifier" every time.)

 private func update(annotation: MKAnnotation?) {
    if #available(iOS 11.0, *) {
        clusteringIdentifier = AnnotationViewInfo.identifier
    }

    // TODO: Update the annotationView

  }
}

Sample Project Here

Seagirt answered 27/4, 2018 at 7:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.