长按UITableView


Answers:


427

首先将长按手势识别器添加到表格视图中:

UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] 
  initWithTarget:self action:@selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];

然后在手势处理程序中:

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    CGPoint p = [gestureRecognizer locationInView:self.myTableView];

    NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    } else if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        NSLog(@"long press on table view at row %ld", indexPath.row);
    } else {
        NSLog(@"gestureRecognizer.state = %ld", gestureRecognizer.state);
    }
}

您必须注意这一点,以免干扰用户对单元格的正常轻敲,并注意handleLongPress可能会触发多次(这是由于手势识别器状态更改所致)。


1
太棒了!!! 非常感谢!但是最后一个小问题:触摸结束时为什么调用handleLongPress方法?
2010年

111
纠正:它会多次触发以指示手势的不同状态(开始,更改,结束等)。因此,在处理程序方法中,请检查手势识别器的state属性,以避免在手势的每个状态下执行操作。例如:if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...

3
别忘了,现在可以将手势识别器直接添加到Interface Builder中的UI元素中,并通过IBAction方法进行连接,因此,此答案甚至更容易;-)(只需记住将识别器附加到 UITableView,而不是UITableViewCell...)

10
还要确认class.h文件中的UIGestureRecognizerDelegate协议
Vaquita,2012年

1
如何防止表格视图导航到单元格中(如果已实现'didSelectRowAtIndexPath'?)
Marchy

46

我已经使用了安娜·卡列尼娜(Anna-Karenina)的答案,并且在出现严重错误的情况下效果很好。

如果您使用的是节,则长按节标题会导致您在按该节的第一行时得到错误的结果,我在下面添加了一个固定版本(包括根据手势状态过滤虚拟呼叫, Anna-Karenina建议)。

- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {

        CGPoint p = [gestureRecognizer locationInView:self.tableView];

        NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
        if (indexPath == nil) {
            NSLog(@"long press on table view but not on a row");
        } else {
            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
            if (cell.isHighlighted) {
                NSLog(@"long press on table view at section %d row %d", indexPath.section, indexPath.row);
            }
        }
    }
}

嗨@mar​​mor:我想问一问,是否可以仅识别出用户触摸过的部分视图?
曼森2014年

嘿,您可以为此使用hitTest(developer.apple.com/library/ios/documentation/uikit/reference/…)。检查此答案,例如有关如何使用的示例:stackoverflow.com/a/2793253/819355
marmor

虽然接受的答案有效。它确实记录了多次火灾,同时在屏幕上拖动时也记录了日志。这个答案没有。合法的复制和粘贴答案。谢谢。
ChrisOSX

29

Swift 5中的答案(Swift中Ricky答案的延续)

将添加UIGestureRecognizerDelegate到您的ViewController

 override func viewDidLoad() {
    super.viewDidLoad()

    //Long Press
    let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
    longPressGesture.minimumPressDuration = 0.5
    self.tableView.addGestureRecognizer(longPressGesture)
 }

和功能:

@objc func handleLongPress(longPressGesture: UILongPressGestureRecognizer) {
    let p = longPressGesture.location(in: self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: p)
    if indexPath == nil {
        print("Long press on table view, not row.")
    } else if longPressGesture.state == UIGestureRecognizer.State.began {
        print("Long press on row, at \(indexPath!.row)")
    }
}

20

这是结合了黎明之歌的答案和马尔默的答案的明确说明。

将长按的Gesture Recognizer拖放到表单元格中。它将跳到左侧列表的底部。

在此处输入图片说明

然后,以与连接按钮相同的方式连接手势识别器。 在此处输入图片说明

将Marmor中的代码添加到动作处理程序中

- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {

    CGPoint p = [sender locationInView:self.tableView];

    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    } else {
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
        if (cell.isHighlighted) {
            NSLog(@"long press on table view at section %d row %d", indexPath.section, indexPath.row);
        }
    }
}

}


2
我认为最好的答案
Asen Kasimov,

8
长按手势识别器应应用于表格视图而不是表格视图单元格。将其放到表格视图单元格中,只有0行在听着长按。
亚历克斯


11

在Swift中回答:

添加代表 UIGestureRecognizerDelegate到您的UITableViewController。

在UITableViewController中:

override func viewDidLoad() {
    super.viewDidLoad()

    let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
    longPressGesture.minimumPressDuration = 1.0 // 1 second press
    longPressGesture.delegate = self
    self.tableView.addGestureRecognizer(longPressGesture)

}

和功能:

func handleLongPress(longPressGesture:UILongPressGestureRecognizer) {

    let p = longPressGesture.locationInView(self.tableView)
    let indexPath = self.tableView.indexPathForRowAtPoint(p)

    if indexPath == nil {
        print("Long press on table view, not row.")
    }
    else if (longPressGesture.state == UIGestureRecognizerState.Began) {
        print("Long press on row, at \(indexPath!.row)")
    }

}

6

基于Anna Karenina的出色回答,我在UITableView上放了一个小类别。

这样,您将拥有一个方便的委托方法,就像处理常规表视图时所习惯的那样。看看这个:

//  UITableView+LongPress.h

#import <UIKit/UIKit.h>

@protocol UITableViewDelegateLongPress;

@interface UITableView (LongPress) <UIGestureRecognizerDelegate>
@property(nonatomic,assign)   id <UITableViewDelegateLongPress>   delegate;
- (void)addLongPressRecognizer;
@end


@protocol UITableViewDelegateLongPress <UITableViewDelegate>
- (void)tableView:(UITableView *)tableView didRecognizeLongPressOnRowAtIndexPath:(NSIndexPath *)indexPath;
@end



//  UITableView+LongPress.m

#import "UITableView+LongPress.h"

@implementation UITableView (LongPress)
@dynamic delegate;

- (void)addLongPressRecognizer {
    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
                                          initWithTarget:self action:@selector(handleLongPress:)];
    lpgr.minimumPressDuration = 1.2; //seconds
    lpgr.delegate = self;
    [self addGestureRecognizer:lpgr];
}


- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    CGPoint p = [gestureRecognizer locationInView:self];

    NSIndexPath *indexPath = [self indexPathForRowAtPoint:p];
    if (indexPath == nil) {
        NSLog(@"long press on table view but not on a row");
    }
    else {
        if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
            // I am not sure why I need to cast here. But it seems to be alright.
            [(id<UITableViewDelegateLongPress>)self.delegate tableView:self didRecognizeLongPressOnRowAtIndexPath:indexPath];
        }
    }
}

如果要在UITableViewController中使用它,则可能需要继承并遵循新协议。

它对我很有用,希望对其他人有帮助!


委派和类别模式的惊人用法
valeCocoa

5

Swift 3答案,使用现代语法,合并其他答案,并消除不需要的代码。

override func viewDidLoad() {
    super.viewDidLoad()
    let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(tablePressed))
    tableView.addGestureRecognizer(recognizer)
 }

@IBAction func tablePressed(_ recognizer: UILongPressGestureRecognizer) {
    let point = recognizer.location(in: tableView)

    guard recognizer.state == .began,
          let indexPath = tableView.indexPathForRow(at: point),
          let cell = tableView.cellForRow(at: indexPath),
          cell.isHighlighted
    else {
        return
    }

    // TODO
}

2

只需将UILongPressGestureRecognizer添加到情节提要中给定的原型单元格,然后将手势拉到viewController的.m文件即可创建操作方法。我做到了,正如我所说。


您能再解释一下吗?您是否将原型单元设置为VC中的属性?
伊桑·帕克

-2

在touchesBegan中使用UITouch timestamp属性可启动计时器或在touchesEnded被触发时停止计时器


感谢您的回答,但是我如何检测触摸涉及到哪一行?
2010年

我可能是错的,但没有提供任何帮助您的方法。您必须使用[tableView indexPathsForVisibleRows]获取当前可见单元格的索引,然后使用一些计算(您的tableView距顶部的偏移量+行的X倍),您将知道手指的坐标位于行。
Thomas Joulin 2010年

我敢肯定,这样做有更简单的方法,如果您有其他想法,我会在这里:)
2010年

我也很高兴知道是否可以做些更简单的事情。但是我认为没有,主要是因为这不是Apple希望我们处理交互的方式……这看起来像是Android认为这种“快速访问菜单”的方式。如果是我的应用程序,我将像Twitter应用程序一样处理它。刷卡到左边显示的选项
托马斯Joulin

是的,我考虑过这一点,因此,如果长按事件真的无法做到这一点,我将使用滑动方法。不过,也许有人在堆栈溢出做到了...
foOg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.