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
}
Related
In my app, I have an mkmapview with annotations.
When I tap annotation some small view with additional informations is appearing.
Now i want to hide this window when i tap the map but no when i tap some annotation.
How to make it?
I think something like this but i dont know how to read it is annotation view tapped.
tap gesture:
let mapTap = UITapGestureRecognizer(target: self, action: #selector(mapDidTap(_:)))
map.addGestureRecognizer(mapTap)
handler:
#objc private func mapDidTap(_ sender: UITapGestureRecognizer) {
if tapIsOnlyMap {
hideSmallPopup()
}
}
You can use var selectedAnnotations: [MKAnnotation] delegate property for detect if any annotation is selected. If there is empty you can hide the window.
One question, how did you open this annotation view when annotation is tapped? I think you can set this 'annotation window' when annotation tapped and then you should not check selectedAnnotations for hide the window.
Enjoy
I have mapView with some annotations. I need to do separate action for both user dragged region change and set region(Automatically focus). Is there any way to find user dragged manually or not while regionDidChangeAnimated method calling.
I have checked all default properties for MKMapView, MKVisibleRect, region. There is no property related to finding for detect map view changed with user dragged manually or not
Unfortunately, you have to do this using a UIPanGestureRecognizer.
I have used, with success, A UIPanGestureRecognizer like the following:
lazy var mapPanGestureRecognizer: UIPanGestureRecognizer = {
let gr = UIPanGestureRecognizer(target: self, action: #selector(draggedMap))
gr.delegate = self
return gr
}()
You will also have to add the UIPanGestureRecognizer to the map with
yourMap.addGestureRecognizer(mapPanGestureRecognizer)
You can then manage what happens in the #selector function by checking the state of the gesture, like so
#objc func draggedMap(panGestureRecognizer: UIPanGestureRecognizer) {
// Check to see the state of the passed panGestureRocognizer
if panGestureRecognizer.state == UIGestureRecognizer.State.began {
// Do something
}
}
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.
}
I see that there are a ton of these questions, and I think I'm following the accepted Swift 3 methodology, but I'm still getting nothing. I can see that the UITapGestureRecognizer has been attached. Here's my code:
let tileClick = UITapGestureRecognizer(target: self, action: #selector(GameManagement.initiateTileClick(_:)))
newView.addGestureRecognizer(tileClick)
newView.isUserInteractionEnabled = true
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
A few things to note:
1) The view that I'm attaching the gesture recognizer to has a two views and a label within it that each cover the entire frame of the view, however, I tried attaching the recognizer to the label, which is the topmost child item and it still doesn't work.
2) Both the function that adds the recognizer and the function that is called on the tap are contained in an NSObject file. I have a variety of interconnected functions that I want to be able to call from multiple view controllers and would prefer to keep this in the separate NSObject file. The process worked when I had everything in a UIViewController file and stopped working when I moved the functions to the NSObject file.
3) I've tried changing GameManagement.initiateTileClick to self.initiateTileClick or just initiateTileClick and none of those worked.
If you are putting your views inside NSObject subclass then these views will lose their behaviors for UIResponder which manages the UI interactions as I am not able to see how you are adding these views to interface.
As you said, it was working inside ViewController because it manages view hierarchy and responder chain.
The solution would be to write extensions to separate code or better abstractions.
extension YourViewController {
newView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(GameManagement.initiateTileClick(_:))))
newView.isUserInteractionEnabled = true
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
}
Giving you an idea how the tap recogniser works.
Firstly add Tap gesture recogniser to your view controller. You have to put the object here as shown in the image.
Then control+drag the tap gesture object to your view and select delegate.
Then control+drag the recogniser to your swift file and action will be like this.
#IBAction func tapGesture(_ sender: UITapGestureRecognizer) {
}
Now you must have seen when you give some input to a text field, the keyboard appears. But if you press outside the text field, that is anywhere in the view, the keyboard hides. This is because of the tap gesture recogniser.
Consider you have a text field such that if you click in that text field, keyboard is appeared. But when you tap outside the textfield, the keyboard must hide.
Add this delegate
UITextFieldDelegate
Implement this:
#IBOutlet var phoneText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
exampleText.delegate = self
}
#IBAction func tapGesture(_ sender: UITapGestureRecognizer) {
exampleText.endEditing(true)
}
Obviously,this function is instance method.
func initiateTileClick(_ sender: UITapGestureRecognizer) {
print("initiate tile click")
}
-
UITapGestureRecognizer(target: self, action:#selector(GameManagement.initiateTileClick(_:)))
but thisGameManagement.initiateTileClick(_:) looks like a class is calling a class method!The target should be the caller of method.self can't call GameManagement.initiateTileClick(_:).
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.