ribl / FBAnnotationClusteringSwift

Swift translation of FB Annotation Clustering, which clusters pins on the map for iOS.
http://ribl.co/blog/2015/05/28/map-clustering-with-swift-how-we-implemented-it-into-the-ribl-ios-app/
MIT License
311 stars 109 forks source link

Annotation disappear after dropping a pin with gesture recognizer on Mapkit #5

Closed mamoun1101 closed 8 years ago

mamoun1101 commented 9 years ago

I have some trouble using UIgesture recognizer and this project

the pins disappear instantly when I drop them.

when I remove animated on viewdidload, I can drop them but they will disappear when I zoom out or in and the cluster is not doing his job too when i'm doing a UIgesture Recognizer.

What I'm doing wrong ?

chenr2 commented 9 years ago

What is the reason behind using UIGestureRecognizer? And what is the relation between animated and viewDidLoad()? And can you send me a small sample project that demonstrates the bug you're experiencing?

mamoun1101 commented 9 years ago

You can see below you project with this class FBViewController: UIViewController with one pices of code I added to drop a pin with UIGesturRecognizer : Just replace your class FBViewController with this code below and you will notice when you drop a pin, it will disappear once you go left or right or zoom out or in in the map. Thank you

class FBViewController: UIViewController {

@IBOutlet weak var mapView: MKMapView!

let numberOfLocations = 1000

let clusteringManager = FBClusteringManager()

override func viewDidLoad() {
    super.viewDidLoad()

    let array:[MKAnnotation] = randomLocationsWithCount(numberOfLocations)

    clusteringManager.addAnnotations(array)
    clusteringManager.delegate = self;

    mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0);
    let uilpgr = UILongPressGestureRecognizer(target: self, action: "action:")
    uilpgr.minimumPressDuration = 0.1
    mapView.addGestureRecognizer(uilpgr)

}

func action(longPressGestureRecognizer:UILongPressGestureRecognizer){
    if longPressGestureRecognizer.state == UIGestureRecognizerState.Began {
        let touchPoint = longPressGestureRecognizer.locationInView(self.mapView)
        let newCoordinate = self.mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView)
        // to know where exactly the pin is (adress)
        let location = CLLocation(latitude : newCoordinate.latitude, longitude:  newCoordinate.longitude)
                     let annotation = MKPointAnnotation()
           annotation.coordinate = newCoordinate
            annotation.title = title
            print("\(title)")
            self.mapView.addAnnotation(annotation)
        }
    }
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// MARK: - Utility

func randomLocationsWithCount(count:Int) -> [FBAnnotation] {
    var array:[FBAnnotation] = []
    for _ in 0...count {
        let a:FBAnnotation = FBAnnotation()
        a.coordinate = CLLocationCoordinate2D(latitude: drand48() * 40 - 20, longitude: drand48() * 80 - 40 )
        array.append(a)
        print("\(array)")
    }
    return array
}

}

chenr2 commented 9 years ago

When you pan the map, regionDidChangeAnimated gets called. Within this delegate method, the clusteringManager will displayAnnotations that intersect with the current map region (clusteredAnnotationsWithinMapRect). In other words, panning the map refreshes it with all the annotations already loaded into the clustering manager.

You probably want to add the annotation to the clustering manager (in addition to dropping it on the map). Within your action method, try adding this line to the end:

clusteringManager.addAnnotations([annotation])
mamoun1101 commented 9 years ago

Awesome thank you ! I have another question, How to retrieve the title and the subtitle of the cluster inside the viewcontroller ?

chenr2 commented 9 years ago

I think it might make more sense to get the title and subtitle of the pin rather than the cluster. This is how you could go about it:

In FBAnnotation.swift, add a subtitle property:

class FBAnnotation : NSObject {
    var coordinate = CLLocationCoordinate2D(latitude: 39.208407, longitude: -76.799555)
    var title: String? = ""
    var subtitle: String? = "" // NEW
}

In ViewController.swift, populate the title and subtitle when you create the random pins:

    func randomLocationsWithCount(count:Int) -> [FBAnnotation] {
        var array:[FBAnnotation] = []
        for _ in 0...count {
            let a:FBAnnotation = FBAnnotation()
            a.coordinate = CLLocationCoordinate2D(latitude: drand48() * 40 - 20, longitude: drand48() * 80 - 40 )
            a.title = "lat: \(a.coordinate.latitude)"  // NEW
            a.subtitle = "long: \(a.coordinate.longitude)" // NEW
            array.append(a)
        }
        return array
    }

Enable the callout when a pin is tapped:

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        var reuseId = ""
        if annotation.isKindOfClass(FBAnnotationCluster) {
            reuseId = "Cluster"
            var clusterView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
            clusterView = FBAnnotationClusterView(annotation: annotation, reuseIdentifier: reuseId)
            return clusterView
        } else {
            reuseId = "Pin"
            var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
            pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            pinView!.pinTintColor = UIColor.greenColor()
            pinView?.canShowCallout = true   // NEW!
            return pinView
        }
    }

Since the gesture recognizer conflicts with the pin callout, comment out the following line:

//        mapView.addGestureRecognizer(uilpgr)