I heard that UISwipeGestureRecognizer can be used to distinguish between a slow swipe and a fast flick. But I can't find any API to tell the difference.
Do you specifically need to use UISwipeGestureRecognizer, or can you use UIPanGestureRecognizer instead? UIPanGestureRecognizer gives you precise movement data whereas UISwipeGestureRecognizer is more basic and just detects whether or not a swipe happened (and in which direction).
UIPanGestureRecognizer has a -velocityInView: method which returns a CGPoint, expressing points per second, vertically and horizontally.
You should use Pan Gesture and find out velocity for better accuracy.
Here is code snip for PanGesture in Swift 5
//Add Pan Gesture on target view in viewDidLoad
let panGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.panGestureDetected))
view.addGestureRecognizer(panGesture)
#objc func panGestureDetected()
{
print("Pan Gesture detected!!")
}
Related
I'm new to coding so I'm trying some small projects in swift. Right now, I'm trying to make a text box inside the ViewController move when the user drags it along the screen. For the text box, I am currently using a UITextField but I have no idea how to program its movement according to drag.
You'll want to add a UIPanGestureRecognizer to your view. There's all sorts of built in gesture recognizers for detecting various gestures like a tap or in this case a pan (drag). You can check them out here: https://developer.apple.com/documentation/uikit/uigesturerecognizer
Here we'll create a pan gesture recognizer, and add it to our view. Assume myView is your UITextField. A good place to do this is in your view controller's viewDidLoad() method.
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(sender:)))
myView.addGestureRecognizer(pan)
The moment your finger touches the screen, we say that a touch sequence has begun. The touch sequence ends when there are no more fingers on the screen. The pan gesture will determine if this touch sequence looks like a pan, and if so, the method handlePan will be called at various stages. Here, the gesture itself will be passed into the method, which we use to determine translation and move our view accordingly. Add this as a method of your view controller.
#objc func handlePan(sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: sender.view)
self.myView.center.x += translation.x
self.myView.center.y += translation.y
sender.setTranslation(CGPoint.zero, in: sender.view)
}
The first line gets the translation in the view which the gesture is attached to (myView). We then adjust myView's position based on this translation, and then we set the translation to zero. This is so that the next time this method is called, the translation will be a delta relative to the previous call.
The property sender.state will tell you the state the gesture is currently in, for example, .began, .changed, .ended. Since a pan is a continuous gesture, our method will be called many times, whenever there's a finger movement.
I want to make a UIButton that when you long press it, it will start recording video and if you pan your finger vertically up (while still long pressing), the video will zoom in.
To my button I added a UILongPressGestureRecognizer and a UIPanGestureRecognizer that does just that. Individually, they work. However, they do not work together.
How can I make my button record when long pressing but also allow me to pan my finger and have that recognized as well? This is how I added my recognizers:
let long = UILongPressGestureRecognizer(target: self, action: #selector(record(gesture:)))
button.addGestureRecognizer(long)
let pan = UIPanGestureRecognizer(target: self, action: #selector(zoom(pan:)))
button.addGestureRecognizer(pan)
You need to confirm the delegate of those two gestures.
for ex:
let long = UILongPressGestureRecognizer(target: self, action: #selector(record(gesture:)))
long.delegate = self
button.addGestureRecognizer(long)
let pan = UIPanGestureRecognizer(target: self, action: #selector(zoom(pan:)))
pan.delegate = self
button.addGestureRecognizer(pan)
and there is a delegate method to recognize multiple gestures simultaneously.
gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
define that in your class and return true.
you will get what you want.
I know this wasn't exactly what the question was asking but you can actually bypass having to use gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) and use UILongPressGestureRecognizer as a UIPanGestureRecognizer using the UIGestureRecognizer.State changes. Thats what i've done in the past, cleans things up and makes more logical sense than having two gesture recognizers
I have a custom UIView that consists of 9 equally-sized subviews. It essentially looks like a tic-tac-toe board.
I've added a UIPanGestureRecognizer to this custom view. Each time the user pans over one of the subviews, I want to take an action. For example, the user could pan over the first 3 (of the 9) subviews in one gesture, and in this case I'd want to take 3 actions.
I could try to do some fancy math and figure out the frame of each subview, then figure out when the gesture crosses from one subview to another. However, I feel like there should be a more elegant way to get a callback when a gesture touches a new UIView. Does a functionality like this exist?
I was able to find a more elegant way by using hitTest, which returns the lowest subview with user interaction enabled. I defined the callback for the pan gesture recognizer as such:
var panSelected = Set<UILabel>()
#objc func handlePan(recognizer: UIPanGestureRecognizer) {
let view = recognizer.view
let loc = recognizer.location(in: view)
if let gridLabel = view?.hitTest(loc, with: nil) as? UILabel {
if !panSelected.contains(gridLabel) {
// my code here
}
}
try to use stack view to group views have same gesture, & using
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(stackViewTapped))
myStackView.addGestureRecognizer(tapGesture)
if there's different method needs to be implemented, just add another stack view.
I have this piece of code
let window = UIApplication.sharedApplication().keyWindow
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
window?.addGestureRecognizer(tap)
It only recognizes Tap (as its tap gesture recognizer), however I want some recognizer to work for all, scroll, pinch, etc.
Also at later point of time I am removing this recognizer.
I read touches began, but how to use it on UIApplication.sharedApplication().keyWindow?
And how to remove that touches began later?
If you want to monitor all touch event then you can subclass UITapGestureRecognizer, this link should help: Monitoring all iOS touches
I'm having an interesting problem with a long press gesture recognizer. I placed one of these on a UITableView, and it only works when I lift my finger after the long press. So basically, I would place my finger on a cell, and then when I lift my finger, it triggers the long press. I figured this out by putting printns when the long press began and ended and both fire after I lift my finger. I think the tableViews default panGestureRecognizer might be interfering with the longPressGestureRecognizer. Here is my code in viewDidLoad:
var longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
longPress.minimumPressDuration = 0.06
longPress.delegate = self
self.tableView.addGestureRecognizer(longPress)
longPress.requireGestureRecognizerToFail(self.tableView.panGestureRecognizer)
Touching down in the cell will not cause the table view's panGestureRecognizer to fail, so delete the requireGestureRecognizerToFail method, and you should then get to the .Began state while your finger is still down.