Detect long press on tableview - ios

I know how to simply detect a long press, but it detect after release. How can I detect the long press without releasing the finger?
This is the code I am using for long press now:
override func viewDidLoad() {
super.viewDidLoad()
setupLongPressGesture()
}
func setupLongPressGesture() {
let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongPress))
longPressGesture.minimumPressDuration = 1.0 // 1 second press
longPressGesture.delegate = self
self.tableView.addGestureRecognizer(longPressGesture)
}
#objc func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer){
if gestureRecognizer.state == .ended {
let touchPoint = gestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
}
}
}

Change .ended to .began.
From the documentation for UILongPressGestureRecognizer:
Long-press gestures are continuous. The gesture begins (UIGestureRecognizer.State.began) when the number of allowable fingers (numberOfTouchesRequired) have been pressed for the specified period (minimumPressDuration) and the touches do not move beyond the allowable range of movement (allowableMovement). The gesture recognizer transitions to the Change state whenever a finger moves, and it ends (UIGestureRecognizer.State.ended) when any of the fingers are lifted.

Related

How do restrict pan gesture recognizers to when a pinch gesture is occurring?

How do you only accept pan gestures when the user is in the process of a pinch gesture? In other words, I'd like to avoid delivering one finger pan gestures.
#IBAction func pinchPiece(_ pinchGestureRecognizer: UIPinchGestureRecognizer) {
guard pinchGestureRecognizer.state == .began || pinchGestureRecognizer.state == .changed,
let piece = pinchGestureRecognizer.view else {
// After pinch releases, zoom back out.
if pinchGestureRecognizer.state == .ended {
UIView.animate(withDuration: 0.3, animations: {
pinchGestureRecognizer.view?.transform = CGAffineTransform.identity
})
}
return
}
adjustAnchor(for: pinchGestureRecognizer)
let scale = pinchGestureRecognizer.scale
piece.transform = piece.transform.scaledBy(x: scale, y: scale)
pinchGestureRecognizer.scale = 1 // Clear scale so that it is the right delta next time.
}
#IBAction func panPiece(_ panGestureRecognizer: UIPanGestureRecognizer) {
guard panGestureRecognizer.state == .began || panGestureRecognizer.state == .changed,
let piece = panGestureRecognizer.view else {
return
}
let translation = panGestureRecognizer.translation(in: piece.superview)
piece.center = CGPoint(x: piece.center.x + translation.x, y: piece.center.y + translation.y)
panGestureRecognizer.setTranslation(.zero, in: piece.superview)
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
You ca use require(toFail:)
as example if you have two gestures tap and swipe
A swipe gesture is a tap followed by a linear movement, whereas a tap is just a tap – we need to make sure the swipe gesture has definitely not been recognizer before the tap gesture is checked.
iOS often does a fairly good job of this, but there’s no need to leave it up to chance: if you call require(toFail:) on the tap gesture recognizer, passing in the swipe recognizer, iOS will definitely make sure they don’t compete:
let swipe = UISwipeGestureRecognizer(target: self, action: #selector(executeSwipe))
let tap = UITapGestureRecognizer(target: self, action: #selector(executeTap))
view.addGestureRecognizer(swipe)
view.addGestureRecognizer(tap)
tap.require(toFail: swipe)
You can enable and disable your gesture easily. When it starts pinching then disable the pan gesture and enable it when it ends pinching. When it starts pan then disable pinch gesture and enable it when end pan.
#IBAction func pinchPiece(_ pinchGestureRecognizer: UIPinchGestureRecognizer) {
guard pinchGestureRecognizer.state == .began || pinchGestureRecognizer.state == .changed,
let piece = pinchGestureRecognizer.view else {
yourPangesture.isEnable = false // Disable Pangesture
// After pinch releases, zoom back out.
if pinchGestureRecognizer.state == .ended {
UIView.animate(withDuration: 0.3, animations: {
pinchGestureRecognizer.view?.transform = CGAffineTransform.identity
})
}
return
}
if pinchGestureRecognizer.state == .end {
yourPangesture.isEnable = true // Enabling again
}
adjustAnchor(for: pinchGestureRecognizer)
let scale = pinchGestureRecognizer.scale
piece.transform = piece.transform.scaledBy(x: scale, y: scale)
pinchGestureRecognizer.scale = 1 // Clear scale so that it is the right delta next time.
}
Do the same for panPiece funtion.

Resolve UITapGestureRecognizer and UILongPressGestureRecognizer simultaneously and fire UIGestureRecognizer.State.began on finger touch down

First of all, none of the already answered questions didn't help me
Swift: Long Press Gesture Recognizer - Detect taps and Long Press
Using tap gesture and long press at the same time in Table View
Long Press Gesture Recognizer Only Fired When Finger is Lifted
And so on
The code working almost fine except one thing: the long press gesture only called when I lift my finger up from the screen. But I need to get behaviour like in Instagram Stories (when you can switch between stories and hold your finger to pause pause some story).
My question is more about how to force UILongPressGesture to fire when user touch finger down, but not up.
Here's my code:
private func setupTapGestures() {
tapRecognizer = UITapGestureRecognizer()
tapRecognizer?.addTarget(self, action: #selector(handleTapGesture(_:)))
tapRecognizer?.delegate = self
view.addGestureRecognizer(tapRecognizer!)
longPressRecognizer = UILongPressGestureRecognizer()
longPressRecognizer?.addTarget(self, action: #selector(handleLongPressGesture(_:)))
longPressRecognizer?.minimumPressDuration = 0.1
longPressRecognizer?.delegate = self
view.addGestureRecognizer(longPressRecognizer!)
}
#objc func handleTapGesture(_ gestureRecognizer: UIGestureRecognizer) {
let width = view.frame.width
let point = gestureRecognizer.location(in: view)
viewModel?.tapAction(viewWidth: width, tapPoint: point)
Swift.print("Tap gesture")
}
#objc func handleLongPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
Swift.print("Began")
} else if gestureRecognizer.state == .ended {
Swift.print("Ended")
}
}
UIGestureRecognizerDelegate:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
// Don't recognize a single tap until a long-press fails
if gestureRecognizer == tapRecognizer && otherGestureRecognizer == longPressRecognizer {
return true
}
return false
}
shouldRequireFailureOf docs
Any suggestions or ideas?
I wonder if your implementation of shouldRequireFailureOf is causing an issue?
This works just fine for me (note: I used .minimumPressDuration = 0.25 because it's a little difficult to tap in under 0.1 seconds):
class GestureTestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupTapGestures()
}
private func setupTapGestures() -> Void {
let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:)))
view.addGestureRecognizer(singleTapGesture)
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:)))
longPressGesture.minimumPressDuration = 0.25
view.addGestureRecognizer(longPressGesture)
}
#objc func handleLongPressGesture(_ gesture: UILongPressGestureRecognizer) -> Void {
if gesture.state == .began {
print("Did Long Press (began)")
}
if gesture.state == .ended {
print("Did Long Press (ended)")
}
}
#objc func handleTapGesture(_ gesture: UITapGestureRecognizer) -> Void {
print("Did Single Tap")
}
}
When I tap, I get "Did Single Tap" in the debug console.
When I tap and hold, I quickly get "Did Long Press (began)", and on finger-lift I get "Did Long Press (ended)"

Using tap gesture and long press at the same time in Table View

I'm building a table view and I cannot seem to get both regular taps and long presses to work.
I have placed this code in my viewDidLoad:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
myTableView.addGestureRecognizer(longPress)
and this code is my gesture recognizer:
#objc func handleLongPress(sender: UILongPressGestureRecognizer){
if UILongPressGestureRecognizer.state == UIGestureRecognizer.State.began {
let touchPoint = UILongPressGestureRecognizer.location(in: self.myTableView)
if let indexPath = self.myTableView.indexPathForRowAtPoint(touchPoint) {
print(indexPath.row)
}
}
}
I have found this code here on Stack Overflow, but I do not think it is up to date for Swift 4 because I can not even run it without the build failing.
UILongPressGestureRecognizer.state should be sender.state and UILongPressGesutreRecognizer.location should be sender.location. Also, the signature for indexPathForRowAtPoint() has been updated to indexPathForRow(at:).
Corrrected code:
#objc func handleLongPress(sender: UILongPressGestureRecognizer) {
if sender.state == .began {
let touchPoint = sender.location(in: self.myTableView)
if let indexPath = self.myTableView.indexPathForRow(at:touchPoint) {
print(indexPath.row)
}
}
}
UILongPressGestureRecognizer is a class name, you need to be calling the class instance.

state began and ended not being triggered

I'm trying to make a button for Taking pictures and recording videos. When a long press is made it will record and 1 tap will take a picture. when button is being pressed i want to transform it to create a effect. however the began and ended is not being triggered since it is not transforming?
func centerButtonPressedDown(sender: UITapGestureRecognizer) {
if !pictureTaken {
delegate?.didLongTapCameraButton()
} else {
}
}
func centerButtonClicked(sender: UITapGestureRecognizer) {
if sender.state == .began {
self.centerButton.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
} else if sender.state == .ended {
self.centerButton.transform = CGAffineTransform.identity
}
}
CenterButton
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(centerButtonClicked)) //Tap function will call when user tap on button
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(centerButtonPressedDown))
tapGesture.numberOfTapsRequired = 1
centerButton.addGestureRecognizer(tapGesture)
centerButton.addGestureRecognizer(longGesture)
I tried your code brother first.It shows me error.Then i modified the code it works fine.
let tapGesture = UITapGestureRecognizer(target: self, action:Selector("centerButtonClicked:")) //Tap function will call when user tap on button
let longGesture = UILongPressGestureRecognizer(target: self, action:Selector("centerButtonPressedDown:"))
tapGesture.numberOfTapsRequired = 1
centerButton.addGestureRecognizer(tapGesture)
centerButton.addGestureRecognizer(longGesture)
func centerButtonPressedDown(sender: UILongPressGestureRecognizer) {
if sender.state == .Began {
print("long press began")
}
else if sender.state == .Ended {
print("long press Ended")
}
}
func centerButtonClicked(sender: UITapGestureRecognizer) {
print("tap is detected")
}
When I single tap the button the printed result is
tap is detected
When I long press the button the printed result is
long press began
long press Ended

UILongPressGestureRecognizer getting fired twice

UILongPressGestureRecognizer is getting fired twice when user long presses on a map for over 2-4 seconds. How can I ensure it will only be fired once?
func action(gestureRecognizer:UIGestureRecognizer) {
println("long pressed on map")
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
if activePlace == -1 {
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
} else {
var uilpgr = UILongPressGestureRecognizer(target: self, action: "action:")
uilpgr.minimumPressDuration = 2.0
myMap.addGestureRecognizer(uilpgr)
}
}
func action(gestureRecognizer:UIGestureRecognizer) {
println("long pressed on map")
var touchPoint = gestureRecognizer.locationInView(self.myMap)
var newCoordinate = myMap.convertPoint(touchPoint, toCoordinateFromView: self.myMap)
var annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
//annotation.title = "New Place"
myMap.addAnnotation(annotation)
var loc = CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude)
}
You have to check the gesture recognizer´s state for the begin of the gesture:
func action(gestureRecognizer:UIGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.Began {
// ...
}
}
Long-press gestures are continuous. The gesture begins (UIGestureRecognizerStateBegan) when the number of allowable fingers (numberOfTouchesRequired) have been pressed for the specified period (minimumPressDuration) and the touches do not move beyond the allowable range of movement (allowableMovement). The gesture recognizer transitions to the Change state whenever a finger moves, and it ends (UIGestureRecognizerStateEnded) when any of the fingers are lifted.
try something like this:
let longGesture = UILongPressGestureRecognizer(target : self,
action : #selector(someFunc(gestureRecognizer:)))
func someFunc(gestureRecognizer: UILongPressGestureRecognizer){
if gestureRecognizer.state == .began {
//do something
}

Resources