UILongPressGestureRecognizer to accept a flexible amount of touches - ios

I have a UILongPressGestureRecognizer which is fired when there is 1 finger on the screen. However, as soon as I put 2 fingers, the function is not fired anymore and I need to create a new gesture for 2 fingers.
How to have UILongPressGestureRecognizer to accept a flexible amount of touches ?
let longScreenGesture = UILongPressGestureRecognizer(target: self, action: #selector(screenTapped(_:)))
longScreenGesture.minimumPressDuration=0.1
longScreenGesture.allowableMovement=0
longScreenGesture.numberOfTouchesRequired=1
sceneView.isMultipleTouchEnabled=true
sceneView.addGestureRecognizer(longScreenGesture)
#objc func screenTapped(_ sender: UILongPressGestureRecognizer)
{
print(sender.numberOfTouches) // -> Always displays 1
}

I ended up using TouchesBegan / Moved / Ended and analyzed gestures by myself

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!

UILongPressGestureReocgnizer is not functioning as it should, and kicks in on movement?

My understanding is once there is a UILongPressGestureRecognizer listener attached to something, e.g. a button, it will fire the selected function, and has 4 default parameters. numbersOfTapsRequired, touchesrequired, min press duration, and allowable movement.
Here's my code:
1) this attaches listener to all backspace buttons:
func attachBackspaceLongPressListeners() {
for button in backspaceButtons {
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(KeyboardViewController.deleteBackwardsLongPress(_:)))
button.addGestureRecognizer(longPress)
}
}
And here is the function it fires:
func deleteBackwardsLongPress(_ gestureRecognizer: UIGestureRecognizer) {
proxy.deleteBackward()
}
It works fine in the simulator, but on the actual keyboard app, it is very jerky. I found however that if after you hold the finger down, and then move it around while still holding, the function fires as expected.

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
}

xcode swift: how to drag a button?

I am working with xcode to create a view that allows users to drag buttons. with the code below, I can move the button to the touch and drag from there, but I cant click the button and drag.
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for obj in touches {
let touch = obj as! UITouch
let location = touch.locationInView(self.view)
word1Button.center = location
}
}
Buttons respond to touch events, so when the user touches down within the bounds of a button the view underneath will not receive those touch events. You can get around this by using a gesture recogniser on your button instead of relying on the lower level touch delivery methods. A long press gesture recognizer would probably work best:
// Where you create your button:
let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
word1Button.addGestureRecognizer(longPress)
//...
func handleLongPress(longPress: UILongPressGestureRecognizer) {
switch longPress.state {
case .Changed:
let point = longPress.locationInView(view)
button.center = point
default:
break
}
}
Note that by default, the UILongPressGestureRecognizer needs the user to hold down for 0.5 seconds before the gesture starts recognizing (and therefore starts dragging). You can change this with the minimumPressDuration property of UILongPressGestureRecognizer. Be careful not to make it too short though - as soon as the gesture recognizes it will cancel other touches to the button, preventing the button action from being fired when the touch is lifted.

Resources