Conflict between pan and swipe gesture in the same view? - uiview

Is there anyway to distinguish pan and swipe gesture in the same view? I have 2 gestures work on a same view simultaneously by using the delegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
I did set the pan gesture's property minimumNumberOfTouches = 1. The problem is when I'm panning, the swipe gesture is triggered. How to make swipe gesture stop when I'm in panning process?

Try to call the requireGestureRecognizerToFail: method in your swipe gesture
[swipeGestureRecognizer requireGestureRecognizerToFail:panGestureRecognizer];
This should cause the pan gesture to cancel the swipe gesture if the pan gesture is recognized or began.

Next-decade solution!
override func viewDidLoad() {
super.viewDidLoad()
let s = UISwipeGestureRecognizer(target: self, action: #selector(bye))
s.direction = .down
view.addGestureRecognizer(s)
let p = UIPanGestureRecognizer(target: self, action: #selector(pan))
p.require(toFail: s)
view.addGestureRecognizer(p)
}
It's that simple now. Both will work.

Related

UIGestureRecognizer.State is 'possible' and not 'recognized' every other click on an MKMapView

I am trying to understand a reproducible bug with my gesture recognisers. I have 2 recognisers on an MKMapView, one UITapGestureRecognizer and one UILongPressGestureRecogniser. Both of them work as expected the first time, however, if I use the long press (which adds an annotation to the map) the next tap gesture will return in the 'possible' state but never hit the 'recognized' state.
▿ Optional<Array<UIGestureRecognizer>>
▿ some : 2 elements
- 0 : <UITapGestureRecognizer: 0x7fda7543ebc0; state = Possible; view = <MKMapView 0x7fda78026e00>>
- 1 : <UILongPressGestureRecognizer: 0x7fda7543e8c0; state = Possible; view = <MKMapView 0x7fda78026e00>; numberOfTapsRequired = 0; minimumPressDuration = 0.2>
After I tap once, and nothing happens, a second tap will then perform the associated function i.e. make it to the recognized state.
I am intercepting all the clicks on the window and the tap definitely takes place each time but the first one after a long press never seems to become accepted. Is there something I'm missing here? The gestures are added as below:
let mapTap = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
mapView.addGestureRecognizer(mapTap)
let pressGesture = UILongPressGestureRecognizer(target: self, action: #selector(mapLongPress(_:)))
pressGesture.minimumPressDuration = 0.2
pressGesture.numberOfTouchesRequired = 1
mapView.addGestureRecognizer(pressGesture)
Could this be to do with the other gestures which are added by default on an MKMapView?
I tried using your code and got the same result.
I solved it with a tricky solution. I hope it would be helpful for you
mapTap = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
mapTap.delegate = self
mapView.addGestureRecognizer(mapTap)
pressGesture = UILongPressGestureRecognizer(target: self, action:
#selector(mapLongPress(_:)))
pressGesture.minimumPressDuration = 0.2
pressGesture.numberOfTouchesRequired = 1
mapView.addGestureRecognizer(pressGesture)
#objc func mapTapped(_ gesture: UITapGestureRecognizer) {
// your code
}
#objc func mapLongPress(_ gesture: UILongPressGestureRecognizer) {
// your code
if gesture.state == .began {
mapTap.isEnabled = false
} else if gesture.state == .cancelled || gesture.state == .ended {
mapTap.isEnabled = true
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
In your case you expect that the tap recognizer as well as the long press recognizer operate simultaneously: When you tap the view, both should start the recognition process. When you end the tap before the minimum tap time for the long press, the tap gesture should fire, but when you end the tap later, the long press gesture should fire.
But the Apple docs say:
UIKit normally allows the recognition of only one gesture at a time on
a single view. Recognizing only one gesture at a time is usually
preferable because it prevents user input from triggering more than
one action at a time. However, this default behavior can introduce
unintended side effects. For example, in a view that contains both pan
and swipe gesture recognizers, swipes are never recognized. Because
the pan gesture recognizer is continuous, it always recognizes its
gesture before the swipe gesture recognizer, which is discrete.
In your case, the long tap gesture recognizer is continuous while the tap gesture recognizer is discrete, so there could be a problem in recognizing the tap.
I would thus try to explicitly allow both recognizers to simultaneous recognice their gestures. An example how to do this is given here.
As soon as the long press recognizer fires, you could cancel the recognition operation of the tap recognizer.
Hope this helps!

Transfer PanGesture to another view

I want to start pan gesture in 1 item. And at the instant the gesture is recognized I create a new item view at the exact same spot and transfer the pan gesture to the new item so the new hovering item moves with the fingers.
How can I do this?
Here is the code so far:
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(useItemPanGesture(_:)))
item.addGestureRecognizer(panGesture)
func useItemPanGesture(panGesture: UIPanGestureRecognizer) {
let newView = createView()
newView.addPanGesture(target: self, action: #selector(self.actualPanGesture(panGesture)))
panGesture.enabled = false
}
func actualPanGesture(panGesture: UIPanGestureRecognizer) {
//do pan gesture stuff
}
I have trouble in the transfer of the pan gesture. Line starting with newView.addPangesture.

iOS: implement one-finger pan and two-finger pan gestures?

The goal is to implement two pan gestures against the same SCNScene: one with one finger and the other with two fingers.
This code below isn't working. The one-finger pan function never gets invoked even though the gesture is assigned a distinct selector. One-finger pans and two-finger pans both invoke sceneViewPannedTwoFingers.
From reading other questions it seemed like shouldRecognizeSimultaneouslyWithGestureRecognizer might be the answer, but these pans are not happening simultaneously. It should be either a one-finger pan or a two-finger pan, never both at once.
Is it possible to have two pan gestures as described above? If so, what's the right way to do this?
// Handle one-finger pans
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(sceneViewPannedOneFinger))
sceneView.addGestureRecognizer(panRecognizer)
// Handle two-finger pans
let twoFingerPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(sceneViewPannedTwoFingers))
sceneView.addGestureRecognizer(twoFingerPanRecognizer)
func sceneViewPannedTwoFingers(sender: UIPanGestureRecognizer) {
print("two finger pan!!!")
}
func sceneViewPannedOneFinger(sender: UIPanGestureRecognizer) {
print("one finger pan!!!")
}
You need to add UIGestureRecognizerDelegate to your view controller and set the gesture recognizers delegate to self inside your view controller. Add the shouldRecognizeSimultaneouslyWithGestureRecognizer method returning true for them. Make sure you set minimum and maximum number of touches also for them.
code like this
class MyClass : UIGestureRecognizerDelegate --< Delegate
func gestureRecognizer(_: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizer) -> Bool
{
return true
}

UITableView can be dragged up and down, not allowing Swipe Gesture?

I am a beginner in Swift, and am trying to add a swipe gesture recognizer to my UIView. I have inserted a gradient CALayer to index 0 to have a gradient background.
My problem is:
Swipe gestures for right and left work fine, but for Down it doesn't work, why?
Set the delegate of swipe gestures that you are adding to the view.
let swipeGesture = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipe:"))
swipeGesture.delegate = self
self.view.addGestureRecognizer(swipeGesture)
self.mySwipeGesture = swipeGesture
GestureRecognizerDelegate asks if two gesture recognizers should be allowed to recognize gestures simultaneously. Return true to allow both gestureRecognizer and otherGestureRecognizer to recognize their gestures simultaneously. The default implementation returns false—no two gestures can be recognized simultaneously. Implement the following delegate to achieve this.
extension ViewController : UIGestureRecognizerDelegate {
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
//Identify gesture recognizer and return true else false.
return gestureRecognizer.isEqual(self.mySwipeGesture) ? true : false
}
}
Swiping Up & Down are the default property of table view. I would suggest you to disable the scrolling of the table view whenever you want to do something on the overlay.
tableView.scrollEnabled = NO;
If you are performing dragging of a particular cell then long press on it and then start dragging.
This is how you can achieve this.
Hope this helps.

Using pan gesture recognizer in SpriteKit

I'm working on a game using SpriteKit and I want to move some sprites around but I need to move only one sprite at a time. How can I use pan gesture recognizer in SpriteKit? I tried with the normal way and I got some errors so I thought maybe it has a special way.
To add a pan gesture recognizer in your game, add the gesture recognizer in your GameScene's didMove method. Then add a new function (handlePanFrom, below) in your GameScene file which will be called when the gesture is recognized.
override func didMove(to view: SKView) {
// Create the gesture recognizer for panning
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanFrom))
// Add the gesture recognizer to the scene's view
self.view!.addGestureRecognizer(panGestureRecognizer)
}
#objc func handlePanFrom(_ recognizer: UIPanGestureRecognizer) {
// This function is called when a pan gesture is recognized. Respond with code here.
}

Resources