如何检测UITableView
中某个单元格的双击?
即我想在用户单次触摸时执行一个操作,如果用户进行双击,我想执行另一个操作?我还需要知道触摸的索引路径。
我如何实现这一目标?
感谢。
答案 0 :(得分:31)
如果您不想创建UITableView
的子类,请使用具有表视图didSelectRowAtIndex:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//checking for double taps here
if(tapCount == 1 && tapTimer != nil && tappedRow == indexPath.row){
//double tap - Put your double tap code here
[tapTimer invalidate];
[self setTapTimer:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Double Tap" message:@"You double-tapped the row" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
[alert release];
}
else if(tapCount == 0){
//This is the first tap. If there is no tap till tapTimer is fired, it is a single tap
tapCount = tapCount + 1;
tappedRow = indexPath.row;
[self setTapTimer:[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(tapTimerFired:) userInfo:nil repeats:NO]];
}
else if(tappedRow != indexPath.row){
//tap on new row
tapCount = 0;
if(tapTimer != nil){
[tapTimer invalidate];
[self setTapTimer:nil];
}
}
}
- (void)tapTimerFired:(NSTimer *)aTimer{
//timer fired, there was a single tap on indexPath.row = tappedRow
if(tapTimer != nil){
tapCount = 0;
tappedRow = -1;
}
}
HTH
答案 1 :(得分:27)
在UITableView
类中覆盖此方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(((UITouch *)[touches anyObject]).tapCount == 2)
{
NSLog(@"DOUBLE TOUCH");
}
[super touchesEnded:touches withEvent:event];
}
答案 2 :(得分:10)
在UITableView
子类中,执行以下操作:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch* touch in touches) {
if (touch.tapCount == 2)
{
CGPoint where = [touch locationInView:self];
NSIndexPath* ip = [self indexPathForRowAtPoint:where];
NSLog(@"double clicked index path: %@", ip);
// do something useful with index path 'ip'
}
}
[super touchesEnded:touches withEvent:event];
}
答案 3 :(得分:9)
首先定义:
int tapCount;
NSIndexPath *tableSelection;
作为.h文件中的类级变量,并进行所有必要的设置。然后...
- (void)tableView(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
tableSelection = indexPath;
tapCount++;
switch (tapCount) {
case 1: //single tap
[self performSelector:@selector(singleTap) withObject: nil afterDelay: .4];
break;
case 2: //double tap
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap) object:nil];
[self performSelector:@selector(doubleTap) withObject: nil];
break;
default:
break;
}
}
#pragma mark -
#pragma mark Table Tap/multiTap
- (void)singleTap {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Single tap detected" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
tapCount = 0;
}
- (void)doubleTap {
NSUInteger row = [tableSelection row];
companyName = [self.suppliers objectAtIndex:row];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"DoubleTap" delegate:nil cancelButtonTitle:@"Yes" otherButtonTitles: nil];
[alert show];
tapCount = 0;
}
答案 4 :(得分:6)
if([touch tapCount] == 1)
{
[self performSelector:@selector(singleTapRecevied) withObject:self afterDelay:0.3];
} else if ([touch tapCount] == 2)
{
[TapEnableImageView cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTapRecevied) object:self];
}
使用performSelector来调用选择器而不是使用计时器。这解决了@ V1ru8提到的问题。
答案 5 :(得分:6)
我选择通过覆盖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");
}
}
答案 6 :(得分:2)
另一个答案
int touches;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
touches++;
if(touches==2){
//your action
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
touches=0;
}
答案 7 :(得分:1)
您可能需要子类化UITableView
并覆盖适当的触摸事件(touchesBegan:withEvent
;,touchesEnded:withEvent
等)。检查事件以查看有多少触摸,并做你的自定义行为。不要忘记拨打UITableView's
触摸方法,否则您将无法获得默认行为。
答案 8 :(得分:1)
根据@lostInTransit我在Swift中准备了代码
var tapCount:Int = 0
var tapTimer:NSTimer?
var tappedRow:Int?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//checking for double taps here
if(tapCount == 1 && tapTimer != nil && tappedRow == indexPath.row){
//double tap - Put your double tap code here
tapTimer?.invalidate()
tapTimer = nil
}
else if(tapCount == 0){
//This is the first tap. If there is no tap till tapTimer is fired, it is a single tap
tapCount = tapCount + 1;
tappedRow = indexPath.row;
tapTimer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "tapTimerFired:", userInfo: nil, repeats: false)
}
else if(tappedRow != indexPath.row){
//tap on new row
tapCount = 0;
if(tapTimer != nil){
tapTimer?.invalidate()
tapTimer = nil
}
}
}
func tapTimerFired(aTimer:NSTimer){
//timer fired, there was a single tap on indexPath.row = tappedRow
if(tapTimer != nil){
tapCount = 0;
tappedRow = -1;
}
}
答案 9 :(得分:1)
来自比较答案的Swift 3解决方案。无需任何扩展,只需添加此代码即可。
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)
}
}
答案 10 :(得分:0)
注意:请看下面的评论,看看虽然这个解决方案对我有用,但它仍然可能不是一个好主意。
创建UITableView
或UITableViewCell
的子类(以及使用计时器)的另一种方法是将UITableViewCell
类扩展为一个类别,例如(使用@oxigen的回答,在这种情况下,对于单元格而不是表格):
@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
这样您就不必使用新的类名重命名UITableViewCell
的现有实例(将扩展该类的所有实例)。
请注意,现在super
在这种情况下(这是一个类别)并不是指UITableView
,而是指其超级UITView
。但是touchesEnded:withEvent:
的实际方法调用位于UIResponder
(其中UITView
和UITableViewCell
都是子类),因此没有区别。
答案 11 :(得分:0)
这是我的完整解决方案:
<强> 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
答案 12 :(得分:0)
oxigen答案的改进。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if(touch.tapCount == 2) {
CGPoint touchPoint = [touch locationInView:self];
NSIndexPath *touchIndex = [self indexPathForRowAtPoint:touchPoint];
if (touchIndex) {
// Call some callback function and pass 'touchIndex'.
}
}
[super touchesEnded:touches withEvent:event];
}
答案 13 :(得分:-1)
此解决方案仅适用于UICollectionView或UITableView的单元格。
首先声明这些变量
int number_of_clicks;
BOOL thread_started;
然后将此代码放入didSelectItemAtIndexPath
中++number_of_clicks;
if (!thread_started) {
thread_started = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
0.25 * NSEC_PER_SEC),
dispatch_get_main_queue(),^{
if (number_of_clicks == 1) {
ATLog(@"ONE");
}else if(number_of_clicks == 2){
ATLog(@"DOUBLE");
}
number_of_clicks = 0;
thread_started = NO;
});
}
0.25是2次点击之间的延迟。我认为0.25非常适合检测这种类型的点击。现在,您只能检测到一次单击和两次单击。祝你好运