Reputation: 374
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
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
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
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