Franck
Franck

Reputation: 374

how to prevent deselection of an annotation automatically swift

I've a view with a map inside. I'd like to achieve the following: when the user taps on the map an annotation is displayed and selected (so the callout bubble is shown) until the user taps another point on the map (in this case, the previous annotation should be removed).

The problem is that when I tap on the map the annotation is added and selected for a little time, then somehow it's deselected (so the callout disappears). I want the callout bubble to persist until the user taps on another point

In the following there is my attempt, could anyone help me, please?

@objc func handleTap(_ sender: UITapGestureRecognizer){

    //...some code that computes the country code starting from latitude and longitude

            var countryCurrency = ""

            func countryRequest(countryLabel: String, completion: @escaping (String)->()){
                //api request that receives the currency name of the country
                completion(countryCurrency)
            }
            countryRequest(countryLabel: countryLabel){ countryCurrency in

                DispatchQueue.main.async {

                    let locat:CLLocationCoordinate2D = CLLocationCoordinate2DMake(locationCoord.latitude, locationCoord.longitude)
                    let annotation = MKPointAnnotation()
                    annotation.coordinate = locat
                    annotation.title = countryCurrency
                    annotation.subtitle = "subtitle"
                    self.mapView.addAnnotation(annotation)
                    self.mapView.selectAnnotation(annotation, animated: true)

                }

            }
}

I also have an extension of the MKMapViewDelegate to customise the callout:

extension MapsItem: MKMapViewDelegate {

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

    if !(annotation is MKPointAnnotation){
        return nil
    }

    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "demo")
    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "demo")
        annotationView!.canShowCallout = true
        annotationView!.sizeToFit()
    }
    else{
        annotationView!.annotation = annotation
    }

    return annotationView

}
}

Thanks in advance!!

Upvotes: 0

Views: 1642

Answers (3)

Dmytro Titov
Dmytro Titov

Reputation: 3201

Both other approaches seem to be suboptimal to me. Selecting on deselect (while tapping) works, but it will re-animate the callout, which might be an undesirable visual effect. Adding a delay has a downside of... having a delay.

I've found a better (in my opinion) solution:

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

This has to be implemented in the UIGestureRecognizerDelegate, attached to the MKMapView. The reason why it fixes the automatic deselection of the annotation is that MKMapView actually has its own built-int gesture recognizers (for supporting standard operations like scrolling the map, zooming in, etc.). And your custom recognizers sometimes get in conflict with them in various odd ways. Implementing this method will prevent it from happening (still preserving the default functionality of the MKMapView).

Upvotes: 0

jdleung
jdleung

Reputation: 1098

Have been looking for a solution, don't know why this happen, is it a bug? By now, I do a trick to delay it showing up. @Sh_Khan 's solution will flash the callout one more time, my solution will let the user has to wait for a while

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {

    let locat:CLLocationCoordinate2D = CLLocationCoordinate2DMake(locationCoord.latitude, locationCoord.longitude)
    let annotation = MKPointAnnotation()
    annotation.coordinate = locat
    annotation.title = countryCurrency
    annotation.subtitle = "subtitle"
    self.mapView.addAnnotation(annotation)
    self.mapView.selectAnnotation(annotation, animated: true)
}

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100503

Try this

set isTappingNow to true before adding annotation and to false after selecting it

   func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView)
   {

      if(!isTappingNow)
      {

           self.mapView.selectAnnotation(view.annotation, animated: false)
      } 

    }

Upvotes: 2

Related Questions