I have a UITapGestureRecognizer which basically performs an action to add a subview. When I tap I only want the subview to load once, however when I tap twice really fast, it performs the action twice. How can I prevent this? Basically after it's tapped once I want the tap gesture recognizer to be disabled temporarily for some seconds. Is there a way to do this?
Disable your tap recognizer in the selector that the recognizer calls. Override didAddSubview in the view to which you add subviews on tapping the recognizer, and re-enable it from there. The recognizer will remain inactive through the time while the new subview is being added. If you animate the addition, you should get a sufficient delay to avoid reacting to double-taps.
You could always use a selector with a delay.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
I would also look into using an NSTimer object.
Related
I have seen storyboard buttons combined with IBAction code as well as UITapGestureRecognizers (not speaking here of programtically defined buttons).
I am curious if there is any (not strongly opinionated) reason to prefer one over the other in specific situations.
Buttons have their own tap action events.
All other UI elements have no.
E.g., if you want to handle label tap event you have to use gesture recognizers.
UIButtons have actions. you don't need tap gesture for it. You may need tap gesture for UILabel or UIView.
In my TVOS app I created a custom gesture recognizer, which is a subclass of a UIGestureRecognizer.
Later in the code I'm trying to add it to a collection view cell.
let customGest:CustomGestureRecognizer = CustomGestureRecognizer(target: self, action: Selector("myMethod:"))
cell.addGestureRecognizer(customGest)
in the debugger I see that my gesture recognizer is getting initialized properly. However, none of it's touches methods are getting called (touchesBegan, touchesMoved..).
I've done this in iOS just fine, so I'm curious if it is possible to do so in TVOS?
Any kind of help is highly appreciated.
Touch events (UITouch) and button press events (UIPress) are first delivered to the focused view, and then they go up the responder chain from there. So your custom gesture recognizer will only fire if the cell you added it to is focused, or if the cell contains the focused view as a descendant.
Is the cell you're adding this gesture to focused (or contain the focused view)?
In my program I have placed a UIButton as a subview of a UIView, both of which have userInteractionEnabled set to true. When the button is tapped, an event is called to handle the button tap, which works as expected. However, the button's UIView superview also handles an event which should not be triggered in this case. Can anybody explain why the UIButton AND UIView are both triggering an event? Any help is appreciated.
Should you resign first responder after the button has done its duty so that the view that the button is in is no longer in control.
How about adding: bringSubviewtoFront:scrollview
to the end of your UIButton code. The idea here is to make your uiview the foremost view; which is what I think is happening when you touch the uiview and thus reactivating the triggering events
I have found a solution: I simply made the button a superview of the view which was handling unwanted events, rather than a subview.
I've set up a UITableView with a double-tap UITapGestureRecognizer. But attempts to double-tap a cell by the user just launches didSelectRowAtIndexPath twice. Are these two supposed to work together?
(i'm aware i could use a single tap gesture recognizer in place of the built-in behavior of didSelectRowAtIndexPath, but here's the problem with that: the cell also has a button that I can't press anymore when i add the single tap gesture recognizer. Also, I've seen examples on SO of users building double tap functionality into didSelectRowAtIndexPath, but isn't that a bit too much of a hack?)
More info about Kris' answer:
cancelsTouchesInView
delaysTouchesBegan
delaysTouchesEnded
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html
In my case I had a problem when adding 2 tap gestures to a UIImageView that was on a custom UITableViewCell. What happened was the didSelectRowAtIndexPath: was called when you tap/double tap on the UIImageView. When I had only one tap gesture, the didSelectRowAtIndexPath: was not called (and for me, that was the right behavior.
To prevent the didSelectRowAtIndexPath: from being called when using two tap gestures (single/double tap), I added this code to the first tap gesture (the single one):
tapGesture.cancelsTouchesInView = YES;
tapGesture.delaysTouchesBegan = YES;
After this change, a tap/double on the UIImageView (on top of the custom cell) did not trigger the didSelectRowAtIndexPath:
Looks like I can get didSelectRowAtIndexPath and the double tap gesture recognizer to play together nicely using the delaysTouchesBegan and cancelsTouchesInView properties of the gesture recognizer.
The other option described by #MSgambel seems to work equally well.
You can use a single-tap gesture recognizer in place of didSelectRowAtIndexPath, even if there is a button in the cell. You just need to check if the touch location is inside the UIButton's view or not in order to handle both cases. Hope that Helps!
I tested the "delayTouchesBegan" method with double taps but I found that the single tap received by the table is then delayed, making the table interaction less responsive to the user, and perhaps annoying.
My solution is a bit pedestrian but I use a timer to detect taps in method didSelectRowAtIndexPath. I record the tap count of "1" for the first tap, and if the user does not tap again with 0.2 seconds it displays the item selected. If the user tapped within 0.2 seconds for tap count "2" then I display another item (an action sheet). I reset the tap count each time.
This method uses more code, but provides quick response from the interface and the user does not need to know what is happening behind the scenes - just that the UI is responsive.
UIScrollView has a canceling mechanism, where it cancels the touch of subviews when it detects 'scrolling'.
I wonder if I can cancel a touch event (which already has begun) programmatically.
I have a draggable view inside a scroll view.
I can let the draggable view receive touches, but I'm wondering how to stop receiving touch events when I want and give touch events to the scroll view.
Have a look at cancelTrackingWithEvent:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIControl_Class/index.html#//apple_ref/occ/instm/UIControl/cancelTrackingWithEvent%3A
You might want to have a look at the UITapGestureRecogniser class's cancelsTouchesInView method
Well I have had a similar problem.
I have solved it by disabling the scroll view when you receive touch event on its subview.
And when you think your event is complete you re-enable the scroll view.
If you do not do enable-disable the scroll view cancels your drag events automatically!