I've got pins placed on a map and when I tap on them I'm calling the didSelect. The function only gets called the first time the pin is tapped, and after that it's not called on that same pin again unless I select another pin and then come back and tap it.
What that sounds like to me is the pin is being selected, and didSelect can only be called in unselected pins, so when I go tap on another pin it's deselecting the first pin and making it tappable again.
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
view.isSelected = false
}
I don't understand why the above code does not work.
How can I allow my annotations be tapped more than one time in a row?
Try with this method deselectAnnotation
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
//do what you need here
mapView.deselectAnnotation(view.annotation, animated: true)
}
Hope this helps
There is another option, and that is to add a Gesture Recognizer for on the annotationView.
This will enable showing the callout view (since de-selecting the annotation immediately will not show it).
internal func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(mapPinTapGestureRecognizer)))
}
#objc private func mapPinTapGestureRecognizer(gestureRecognizer: UITapGestureRecognizer) {
// Will get called on the second time the pin is selected.
// And then, after that, it will be called every time.
}
Just don't forget to remove the recognizer when the annotation is no longer selected.
internal func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
// Remove the gesture recognizer when the annotation is no longer selected.
}
Related
I'm using the default Google Map recenter button which is shown by default. How do I ensure that the recenter button is not shown by default and it's only shown when someone moves the map using Swift?
func SetupMap() {
googleMapView.settings.myLocationButton = true
}
That's pretty easy. You know how to toggle the visibility of the myLocationButton, so what's left is to think harder.
If you take time to review the GoogleMap's GMSMapViewDelegate, you will see that there are couple of methods/functions that will allow you to further your idea.
So set your mapView's delegate to your class (controller), and conform to that GMSMapViewDelegate protocol, and then implement those methods.
willMove
didChange position
These are all you need.
The willMove gets invoked when you start dragging the mapView. On the other hand, the didChange position gets called when the camera did change.
If you do these things, you'll get even nearer towards your goal. However, you might need some debounce feature in your code, because you only want to hide the location button just once, just after the user stops dragging the camera.
var debounce_timer: Timer?
extension MapsViewController: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
print("GMS: will move")
mapView.settings.myLocationButton = true
}
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
print("GMS: didChane camera position")
debounce_timer?.invalidate()
debounce_timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in
mapView.settings.myLocationButton = false
}
}
}
Voila!
Demo:
Swift 4 iOS 11.x
Learning about mapViews and annotations and I can quite get my mind around some functionality I would like to do.
I create a mapView, and I add an annotation to it with a button, so far so good. I want the button to be a delete pin one, so it looks like this.
Now when I click on the blue no entry I want it to delete the black pin that it is connected too. But how to trace the link of the annotation to its pin. I get a call back with the button and thru the accessory view. I can lookup the title of the view and find the link, but surely there is a better method.
You need to use this method func mapView(_ mapView: MKMapView,annotationView view: MKAnnotationView,calloutAccessoryControlTapped control: UIControl) of MKMapViewDelegate
Something like this
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView,
calloutAccessoryControlTapped control: UIControl) {
//Here you have the annotation that was selected
let selectedAnnotation = view.annotation
//Do whatever you need here
}
I'm trying to figure out how to add a Long press gesture to a map annotation(Mapbox).I have my code set up so that when a user tap's the annotation they segue to another view by putting my code in this function.
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
}
Now I want to allow a user to segue to another view by holding the same annotation. I tried to use and if and else statement in the code above but the Long press gesture doesn't work unless I tap the annotation first to activate the function so the if and else statement can start working. But I dont want the user to tap then hold. I just want them to either tap or hold down on the annotation.
Thank You for your answers in advance
I'm not familiar with the Mapbox API but if there's no proper delegate method try your own custom implementation with uigesturerecognizer and delegation.
set your gesture recognizer on the annotation view:
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressDetected))
annotation.view.addGestureRecognizer(longPressGestureRecognizer)
make a delegate
weak var delegate: AnnotationViewDelegate?
and a protocol AnnotationViewDelegate in Annotation subclass:
protocol AnnotationViewDelegate: class {
func annotationDidDetectLongPress()
}
implement long press handler and notify the delegate about long tap inside
func longPressDetected(sender: UILongPressGestureRecognizer) {
// here you should notify the delegate
delegate?.annotationDidDetectLongPress()
}
assign delegate to self in controller and implement
func annotationDidDetectLongPress() {
// done
}
Currently I have a map that has several Annotations.
For the Annotations I have
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView){
// Do your annotation click work
}
Is it possible to do this for tapping the Map only and not the Annotation and how can I do it?
In ViewWillAppear method :
let gestureRecognizer = UITapGestureRecognizer(target: self, action:"triggerTouchAction:")
mapView.addGestureRecognizer(gestureRecognizer)
And Whatever information you want to show just add code in following method :
func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) {
//Add alert to show it works
}
Hope it going to help you to resolve issue.
How do you always show the annotation callouts, i.e. don't hide them when you tab the map view?
Resetting the annotations also will bring the callout to view state true.
[mapView removeAnnotation: currentMarker];
[mapView addAnnotation:currentMarker];
The callout is shown when an MKAnnotationView is selected and the view's canShowCallout property is set to YES.
It is then hidden when that MKAnnotationView is deselected. This occurs by tapping another annotation view, or by tapping outside of the currently selected annotation view.
As the delegate of MKMapView (conforming to MKMapViewDelegate), you are told when an annotation view is selected and deselected, but it's too late to do anything about it.
If you want to not deselect an annotation view, you should subclass MKAnnotationView and override the setSelected:animated: method and stop the annotation view from being deselected.
Thanks, #Zumry Mohammed for this idea. This solution in swift works for me:
func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
guard let ann = view.annotation else {return}
mapView.removeAnnotation(ann)
mapView.addAnnotation(ann)
mapView.selectAnnotation(ann, animated: false)
}
I just set isSelected property to true on viewFor annotation method and that is all.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annotationV = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationV.image = UIImage(named: "ZeusSurveyMarkerTaskIcon", in: Bundle(for: ZsurveysGeofenceLocationMapView.self), compatibleWith: nil)
annotationV.canShowCallout = true
annotationV.isSelected = true
return annotationV
}