UITapGestureRecognizer doubletap still triggers singletap action - ios

I have an UIView with both single and double tap recognizers but with different actions of course. The single tap recognizer works well but the double tap recognizer still calls and triggers the single tap...
Below is my implementation:-
let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(toggleIsVisible))
singleTapGesture.numberOfTapsRequired = 1
self.addGestureRecognizer(singleTapGesture)
let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(test))
doubleTapGesture.numberOfTapsRequired = 2
self.addGestureRecognizer(doubleTapGesture)
singleTapGesture.require(toFail: doubleTapGesture)
singleTapGesture.delaysTouchesBegan = true
doubleTapGesture.delaysTouchesBegan = true
Note: "self" is a UIView class

You can achieve it like this as well ... add delay to your single tap to check if its double tap.. if double tap then cancel performance of single tap .. simple methodology
var tapCount = 0
func tapGestureRecognizer() {
tapCount += 1
switch (tapCount)
{
case 1: //single tap
self.perform(#selector(singleTap), with: nil, afterDelay: 0.2)
case 2: //double tap
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(singleTap), object: nil)
doubleTap()
break;
default:
break;
}
if (tapCount>2){
tapCount = 0
}
}
#objc func singleTap(){
}
#objc func doubleTap() {
}

Your code should work fine without triggering the singleTap gesture for doubleTap events. So why is the singleTap event gesture triggering for doubleTap event? Are you sure these are the only gestures you're adding? Make sure you're not adding any other customisation that might alter the gesture events. You don't need these lines:
singleTapGesture.delaysTouchesBegan = true
doubleTapGesture.delaysTouchesBegan = true

Related

Calling Long Press Button action only once not rapid fire

Here is my code for a long press. When I long-press the button, it keeps getting called. How do I set it up so it only gets called once and then gets called again only once the finger is release and the long press is started again?
let tapGesture = UITapGestureRecognizer(target: self, action: #selector (tap))
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(long))
tapGesture.numberOfTapsRequired = 1
self.reminderButton.addGestureRecognizer(tapGesture)
self.reminderButton.addGestureRecognizer(longGesture)
use this code in your selector
#objc func gestureAction(gesture: UIGestureRecognizer) {
if let longPress = gesture as? UILongPressGestureRecognizer {
if longPress.state == UIGestureRecognizer.State.began {
} else {
}
}

Touch down repeat event does not works

I want my button to change its background image when the user clicks on it twice. For this purpose i am using touchDownRepeat event. However it does not works.
button.addTarget(self, action: #selector(clickedRepeatOnPlate), for: .touchDownRepeat)
As for the Apple's oficial documentation about .touchDownRepeat :
A repeated touch-down event in the control; for this event the value of the UITouch tapCount method is greater than one.
This event will trigger every time the user taps the button more than once, so four taps will trigger the event three times.
To trigger only double taps, you need to create a UITapGesture and set 2 on its numberOfTapsRequired:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickedRepeatOnPlate))
tapGesture.numberOfTapsRequired = 2
button.addGestureRecognizer(tapGesture)
Edit
If you need to get the sender button as a function parameter, you can do as follows:
func addDoubleTapEvent() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickedRepeatOnPlate(gesture:)))
tapGesture.numberOfTapsRequired = 2
button.addGestureRecognizer(tapGesture)
}
#objc func clickedRepeatOnPlate(gesture: UITapGestureRecognizer) {
guard let button = gesture.view as? UIButton else { return }
print(button.titleLabel?.text)
}
Output
Optional("button")
This let you to set a gesture for double tap on a view.
let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTapped))
tap.numberOfTapsRequired = 2
view.addGestureRecognizer(tap)
Remember that a UIButton is a UIView

Getting Tag from Tap Gesture Recognizer

I've got an array of UIImageViews and have programmatically assigned tap gesture recognizers to them.
myImages.forEach{ UIImageView in
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(gesture:)))
tap.numberOfTapsRequired = 1
tap.delegate = self
view.addGestureRecognizer(tap)
}
What's the best way to assign a sender to each (or determine which image was tapped another way)? I've unsuccessfully tried
var tag = sender.view!.tag
Thanks!
in here you need to follow two steps,
step 1
assign the tags for imageview before append to your myImages array.
step 2
get the tag from imageview array and assign to your each gesture
myImages.forEach{
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
tap.numberOfTapsRequired = 1
tap.view?.tag = $0.tag
$0.isUserInteractionEnabled = true
$0.addGestureRecognizer(tap)
}
and handle the func like
#objc func handleTap(_ sender: UITapGestureRecognizer) {
guard let getTag = sender.view?.tag else { return }
print("getTag == \(getTag)")
}
You can use the block provided by UITapGestureRecognizer init to access your images in place.
myImages.forEach { image in
let tap = UITapGestureRecognizer(block: {[weak self] _ in
//Do your stuff here
//print("Image Tapped:", image.debugDescription)
}, delegate: self)
tap.numberOfTapsRequired = 1
image.addGestureRecognizer(tap)
}
If you want to set UITapGestureRecognizer in UICollectionView or UITableView cell then below solution is useful for us.
Step 1 Assign the UITapGestureRecognizer to particuller textview or other view in UICollectionView or UITableView cell.
cell.textView?.delegate = self
cell.textView?.isEditable = false
cell.textView?.isSelectable = true
let tap = UITapGestureRecognizer(target: self, action:#selector(self.onclickLink(_:)))
cell.textView?.tag = indexPath.row
tap.numberOfTapsRequired = 1
cell.textView?.addGestureRecognizer(tap)
Step 2 Get the tag from UITextView or other View in onclick action.
#IBAction func onclickLink(_ sender: UITapGestureRecognizer) {
print("indexPathRow == \(sender.view?.tag ?? 0)")
}

programmatically simulate a swipe gesture in Swift

I am implementing a gesture recognizer for swiping in Swift. I wan to be able to simulate the flinging of the card (programmatically swipe the view).
I assumed there would be a built in function for this but all I have found is one for tap gesture not swipe gesture.
This is how I am implementing the swipe gesturing:
let gesture = UIPanGestureRecognizer(target: self, action: Selector("wasDragged:"))
cardView.addGestureRecognizer(gesture)
cardView.userInteractionEnabled = true
}
func wasDragged (gesture: UIPanGestureRecognizer) {
let translation = gesture.translationInView(self.view)
let cardView = gesture.view!
// Move the object depending on the drag position
cardView.center = CGPoint(x: self.view.bounds.width / 2 + translation.x,
y: self.view.bounds.height / 2 + translation.y)
You can't simulate a gesture recognizer in its full implications (I mean, you can't actually make iOS think it's a real user action).
You can, however, fool your own code making it act as if it were a real swipe. For that, you need to create a gesture recognizer first:
var gestureRecognizerSwipeRight = UISwipeGestureRecognizer(target: self, action: "activatedGestureRecognizer:")
gestureRecognizerSwipeRight.direction = UISwipeGestureRecognizerDirection.Right
yourView.addGestureRecognizer(gestureRecognizerSwipeRight)
And then pass it directly to your action:
// Some other place in your code
self.activatedGestureRecognizer(gesture: gestureRecognizerSwipeRight)
Your activatedGestureRecognizer(gesture:) method should be something like:
func activatedGestureRecognizer(gesture: UIGestureRecognizer) {
if let gestureRecognizer = gesture as? UIGestureRecognizer {
// Here you can compare using if gestureRecognizer == gestureRecognizerSwipeRight
// ...or you could compare the direction of the gesture recognizer.
// It all depends on your implementation really.
if gestureRecognizer == gestureRecognizerSwipeRight {
// Swipe right detected
}
}
}
In fairness, I don't see any real gain in doing it this way. It should be a lot better to simply do the action associated with the swipe instead of actually simulating the gesture recognizer.
If you need, for instance, to animate your card while swipping, why don't you simply disable the user interaction on your card view and animate it programmatically?
Here is code you can use to programatically swipe the cell. When performed, the cell will animate to the swiped position.
#IBAction
func swipeFirstCell() {
if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) {
tableView.perform(Selector("_endSwipeToDeleteRowDidDelete:"), with: nil) // cancel any existing swipes
tableView.perform(Selector("_swipeToDeleteCell:"), with: cell)
}
}
Note you need to also return true for the cell from canEditRowAtIndexPath.
This might get flagged by Apple's private API detection but you can at least use it for development and perhaps obfuscate the string if you really to.
For SWIFT 3.0
let swipeRightOrange:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(slideToRightWithGestureRecognizer))
swipeRightOrange.direction = .Right;
let swipeLeftOrange:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(slideToLeftWithGestureRecognizer))
swipeLeftOrange.direction = .Left;
#IBAction func slideToLeftWithGestureRecognizer(gestureRecognizer:UISwipeGestureRecognizer)
{
viewOrange.backgroundColor = UIColor.blue
}
#IBAction func slideToRightWithGestureRecognizer(gestureRecognizer:UISwipeGestureRecognizer)
{
viewOrange.backgroundColor = UIColor.lightGray
}
You can create the UIPanGestureRecognizer by yourself and pass it to the wasDragged method. You should check with different values of the translation though:
let gesture = UIPanGestureRecognizer()
gesture.setTranslation(CGPointMake(0, 100), inView: self.view)
wasDragged(gesture)
SWIFT 4.2
let gesture = UIPanGestureRecognizer()
gesture.setTranslation(CGPoint(x: 0, y: 100), in: self.view)
wasDragged(gesture)
Although I asume you need something else. Why do you need to simulate this gesture in the first place?
You need to implement UISwipeGestureRecognizer
override func viewDidLoad() {
super.viewDidLoad()
var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
self.view.addGestureRecognizer(swipeRight)
var swipeDown = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeDown.direction = UISwipeGestureRecognizerDirection.Down
self.view.addGestureRecognizer(swipeDown)
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
print("Swiped right")
case UISwipeGestureRecognizerDirection.Down:
print("Swiped down")
case UISwipeGestureRecognizerDirection.Left:
print("Swiped left")
case UISwipeGestureRecognizerDirection.Up:
print("Swiped up")
default:
break
}
}
}

Single tap, created by UITapGestureRecognizer, doesn't work on UIButton

I have a lot of UIButtons without any acion. I want call some action in tap handler function. I create single tap with UITapGestureRecognizer. When I tap not on my UIButton, single tap handler work. When I tap on my UIButton, I see animation of pressing this button, but single tap handler doesn't work. Also I create double tap, and it works fine.
Question №1
What I can do with single tap? Handler should work, when I tap on my UIButton.
Question №2
How I can get UIButton in tap handler? I need get text label from this button.
Part of my code:
override func viewDidLoad() {
...
let singleTap = UITapGestureRecognizer(target: self, action: "singleTap:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
view.addGestureRecognizer(singleTap)
let doubleTap = UITapGestureRecognizer(target: self, action: "doubleTap:")
doubleTap.numberOfTapsRequired = 2
doubleTap.numberOfTouchesRequired = 1
view.addGestureRecognizer(doubleTap)
singleTap.requireGestureRecognizerToFail(doubleTap)
...
}
func doubleTap(sender: UIGestureRecognizer) {
if sender.state == .Ended {
print("doubleTap")
}
}
func singleTap(sender: UIGestureRecognizer) {
if sender.state == .Ended {
print("singleTap")
}
}
func addButton(time:String, x:CGFloat, y:CGFloat, width:CGFloat, height:CGFloat, tag: Int) -> UIButton {
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(x, y, width, height)
button.setTitle(time, forState: UIControlState.Normal)
button.tag = tag
self.scrollView.addSubview(button)
return button
}
If you want to add TapGesture into Button then do it like this way:
let singleTap = UITapGestureRecognizer(target: self, action: "singleTap:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
yourButton.addGestureRecognizer(singleTap)

Resources