How can I detect a double tap on a certain cell in UITableView
?
i.e. I want to perform one action if the user made a single touch and a
Swift 3 solution from compare answers. No need any extensions, just add this code.
override func viewDidLoad() {
viewDidLoad()
let doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(sender:)))
doubleTapGestureRecognizer.numberOfTapsRequired = 2
tableView.addGestureRecognizer(doubleTapGestureRecognizer)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(sender:)))
tapGestureRecognizer.numberOfTapsRequired = 1
tapGestureRecognizer.require(toFail: doubleTapGestureRecognizer)
tableView.addGestureRecognizer(tapGestureRecognizer)
}
func handleTapGesture(sender: UITapGestureRecognizer) {
let touchPoint = sender.location(in: tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
print(indexPath)
}
}
func handleDoubleTap(sender: UITapGestureRecognizer) {
let touchPoint = sender.location(in: tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
print(indexPath)
}
}
Another answer
int touches;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
touches++;
if(touches==2){
//your action
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
touches=0;
}
I chose to implement it by overriding the UITableViewCell
.
MyTableViewCell.h
@interface MyTableViewCell : UITableViewCell
@property (nonatomic, assign) int numberOfClicks;
@end
MyTableViewCell.m
@implementation MyTableViewCell
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
self.numberOfClicks = [aTouch tapCount];
[super touchesEnded:touches withEvent:event];
}
TableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *myCell = (MyTableViewCell*) [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(@"clicks:%d", myCell.numberOfClicks);
if (myCell.numberOfClicks == 2) {
NSLog(@"Double clicked");
}
}
You'll probably need to subclass UITableView
and override whatever touch events are appropriate (touchesBegan:withEvent
;, touchesEnded:withEvent
, etc.) Inspect the events to see how many touches there were, and do your custom behavior. Don't forget to call through to UITableView's
touch methods, or else you won't get the default behavior.
Note: please see the comments below to see though while this solution worked for me, it still may not be a good idea.
An alternative to creating a subclass of UITableView
or UITableViewCell
(and to using a timer) would be just to extend the UITableViewCell
class with a category, for example (using @oxigen's answer, in this case for the cell instead of the table):
@implementation UITableViewCell (DoubleTap)
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(((UITouch *)[touches anyObject]).tapCount == 2)
{
NSLog(@"DOUBLE TOUCH");
}
[super touchesEnded:touches withEvent:event];
}
@end
This way you don't have to go around renaming existing instances of UITableViewCell
with the new class name (will extend all instances of the class).
Note that now super
in this case (this being a category) doesn't refer to UITableView
but to its super, UITView
. But the actual method call to touchesEnded:withEvent:
is in UIResponder
(of which both UITView
and UITableViewCell
are subclasses), so there's no difference there.
Here's my complete solution:
CustomTableView.h
//
// CustomTableView.h
//
#import <UIKit/UIKit.h>
@interface CustomTableView : UITableView
// Nothing needed here
@end
CustomTableView.m
//
// CustomTableView.m
//
#import "CustomTableView.h"
@implementation CustomTableView
//
// Touch event ended
//
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// For each event received
for (UITouch * touch in touches) {
NSIndexPath * indexPath = [self indexPathForRowAtPoint: [touch locationInView:self] ];
// One tap happened
if([touch tapCount] == 1)
{
// Call the single tap method after a delay
[self performSelector: @selector(singleTapReceived:)
withObject: indexPath
afterDelay: 0.3];
}
// Two taps happened
else if ([touch tapCount] == 2)
{
// Cancel the delayed call to the single tap method
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: @selector(singleTapReceived:)
object: indexPath ];
// Call the double tap method instead
[self performSelector: @selector(doubleTapReceived:)
withObject: indexPath ];
}
}
// Pass the event to super
[super touchesEnded: touches
withEvent: event];
}
//
// Single Tap
//
-(void) singleTapReceived:(NSIndexPath *) indexPath
{
NSLog(@"singleTapReceived - row: %ld",(long)indexPath.row);
}
//
// Double Tap
//
-(void) doubleTapReceived:(NSIndexPath *) indexPath
{
NSLog(@"doubleTapReceived - row: %ld",(long)indexPath.row);
}
@end