As the title reads, my problem is that my UILongPressGestureRecognizer sometimes does not run the code inside the sender.state = .ended. The .began always runs and works. I have tried to notice pattern but is to infrequent and I have not found a valid pattern or causation. I simply add my UITapGestureRecognizer UILongPressGestureRecognizer to my button:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(normalTap(_:)))
tapGesture.numberOfTapsRequired = 1
camButton.addGestureRecognizer(tapGesture)
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
longGesture.minimumPressDuration = 0.10
camButton.addGestureRecognizer(longGesture)
And then here is my longTap function:
#objc func longTap(_ sender: UIGestureRecognizer) {
if sender.state == .ended {
if movieOutput.recordedDuration.seconds == lastRecordDuration || movieOutput.recordedDuration.seconds <= 0.35 {
capturePhoto()
} else {
stopRecording()
}
} else if sender.state == .began {
startCapture()
}
}
I use the longPress for video and photos, and the TapGesture for photos only. Im using AVFoundation.
After receiving assistance from #rmaddy, the solution is basically to implement a .cancelled state action. For some reason the continuous gesture of UILongPressGesture got cancelled. In my code I implemented a `if sender.state == .cancelled.
I know this is old question, but writing for those who are facing issue like me.
You can get sender.state == .possible when tap is ended.
Related
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.
I have a UIView that I added a UILongPressGestureRecognizer to so that I can handle clicks and have that UIView work like a button.
let longPressGtr = UILongPressGestureRecognizer(target: self, action:#selector(longPressSelector))
longPressGtr.minimumPressDuration = 0.1
myView.isUserInteractionEnabled = true
myView.addGestureRecognizer(longPressGtr)
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
myView.backgroundColor = UIColor.gray
} else if gestureRecognizer.state == .ended {
myView.backgroundColor = UIColor.blue // my button is blue
doSomething()
}
}
func doSomething() {
print("view was pressed")
}
This works, but the one thing that doesn't is when I press and hold on my UIView but drag my finger off the view, the "button" doesn't unselect. It still fires doSomething(). A regular UIButton will deselect the button and not fire it's onClick if you are holding down on it an drag your finger off the view.
How can I implement this functionality into my UIView?
Or is there a better way to make a UIView act like a button?
You need to check whether the gesture is inside the view.
#objc func longPresserDidFire(_ presser: UILongPressGestureRecognizer) {
let gestureIsInside = myView.point(inside: presser.location(in: myView), with: nil)
switch presser.state {
case .began, .changed:
if gestureIsInside {
myView.backgroundColor = .blue
} else {
myView.backgroundColor = .gray
}
case .cancelled:
myView.backgroundColor = .gray
case .ended:
myView.backgroundColor = .gray
if gestureIsInside {
doSomething()
}
default: break
}
}
You are not adding condition of gestureRecognizer state changed that's why it is accepting the end state.
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == .began {
} else if gestureRecognizer.state == .changed {
}else if gestureRecognizer.state == .ended {
}
}
Add one more condition and check if it works.
When you drag your finger outside of the view, gestureRecognizer is probably translated to failed or cancelled state, so you need to add handling of this cases gestureRecognizer.state == .failed and gestureRecognizer.state == .cancelled.
#objc func longPressSelector(_ gestureRecognizer: UILongPressGestureRecognizer) {
}
Place UILongPressGestureRecognizer instead of UITapGestureRecognizer and check it
I have a SpringButton which I want to drag. This is my code:
var gesture = UIPanGestureRecognizer(target: self, action: #selector(userDragged))
card.addGestureRecognizer(gesture)
var cardIsCurrentlyMoving = false
func userDragged(gesture: UIPanGestureRecognizer){
if !cardIsCurrentlyMoving{
if let button = gesture.view as? SpringButton {
if gesture.state == .began {
print("begon")
cardIsCurrentlyMoving = true
startPosition = button.center
} else if gesture.state == .changed {
print("changed")
} else if gesture.state == .ended{
print("ended")
cardIsCurrentlyMoving = false
}
}
}
}
The function gets called, and the state gets changed to .began. However, when trying to move the button nothing happens. This is because cardIsCurrentlyMoving is set to true in .began, but never back to false, because gesture.state .changed and .ended never gets called.
When I release my finger and touch the button again, nothing happens as well. Why does UIPanGestureRecognizer not executes .changed and .ended?
Thanks.
I think you need to check your if statement
if !cardIsCurrentlyMoving{
}
Pan Gesture continuously calls method with changed state. So userDragged func called continuously but just because of your above if statement, control doesn't go inside if statement.
So i'll suggest to use this, instead of yours.
func userDragged(gesture: UIPanGestureRecognizer){
if let button = gesture.view as? SpringButton {
if gesture.state == .began {
print("begon")
cardIsCurrentlyMoving = true
startPosition = button.center
} else if gesture.state == .changed {
print("changed")
} else if gesture.state == .ended{
print("ended")
cardIsCurrentlyMoving = false
}
}
}
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
I'm having a little trouble with the gestures.
I'm trying to use both tap and long press on the same button, so I've used
#IBAction func xxx (sender: UITapGestureRecognizer)
and
#IBAction func xxx (sender: UILongPressGestureRecognizer)
but my button seems to react to both functions when I tap. What might be wrong?
func long(longpress: UIGestureRecognizer){
if(longpress.state == UIGestureRecognizerState.Ended){
homeScoreBool = !homeScoreBool
}else if(longpress.state == UIGestureRecognizerState.Began){
print("began")
}
}
Hard to say what´s not working with your code, with the only two rows that you have provided, but I would recommend you to do it in this way instead:
Create an outlet to your button instead
#IBOutlet weak var myBtn: UIButton!
And in your viewDidLoad() add the gestures to the buttons
let tapGesture = UITapGestureRecognizer(target: self, action: "normalTap")
let longGesture = UILongPressGestureRecognizer(target: self, action: "longTap:")
tapGesture.numberOfTapsRequired = 1
myBtn.addGestureRecognizer(tapGesture)
myBtn.addGestureRecognizer(longGesture)
And then create the actions to handle the taps
func normalTap(){
print("Normal tap")
}
func longTap(sender : UIGestureRecognizer){
print("Long tap")
if sender.state == .Ended {
print("UIGestureRecognizerStateEnded")
//Do Whatever You want on End of Gesture
}
else if sender.state == .Began {
print("UIGestureRecognizerStateBegan.")
//Do Whatever You want on Began of Gesture
}
}
Swift 3.0 version:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.normalTap))
let longGesture = UILongPressGestureRecognizer(target: self, action: Selector(("longTap:")))
tapGesture.numberOfTapsRequired = 1
myBtn.addGestureRecognizer(tapGesture)
myBtn.addGestureRecognizer(longGesture)
func normalTap(){
print("Normal tap")
}
func longTap(sender : UIGestureRecognizer){
print("Long tap")
if sender.state == .ended {
print("UIGestureRecognizerStateEnded")
//Do Whatever You want on End of Gesture
}
else if sender.state == .began {
print("UIGestureRecognizerStateBegan.")
//Do Whatever You want on Began of Gesture
}
}
Updated syntax for Swift 5.x:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(normalTap))
button.addGestureRecognizer(tapGesture)
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap))
button.addGestureRecognizer(longGesture)
#objc func normalTap(_ sender: UIGestureRecognizer){
print("Normal tap")
}
#objc func longTap(_ sender: UIGestureRecognizer){
print("Long tap")
if sender.state == .ended {
print("UIGestureRecognizerStateEnded")
//Do Whatever You want on End of Gesture
}
else if sender.state == .began {
print("UIGestureRecognizerStateBegan.")
//Do Whatever You want on Began of Gesture
}
}