2010-10-13 2 views
165

Я хочу обработать длинное нажатие на UITableViewCell, чтобы напечатать «меню быстрого доступа». Кто-то уже сделал это?Длинное нажатие на UITableView

В частности, распознать жест на UITableView?

ответ

403

Сначала добавьте длинный пресс жест распознаватель в виде таблицы:

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); 
    } 
} 

Вы должны быть осторожны с этим, так что это не мешает нормальному постукивания пользователя ячейки, а также отметить, т hat handleLongPress может срабатывать несколько раз (это будет связано с изменением состояния распознавателя жестов).

+1

Awesome !!! Большое спасибо! Но последний маленький вопрос: почему метод handleLongPress вызывается, когда контакт закончился? – foOg

+0

Он не вызывается при касании, но может срабатывать несколько раз, если пользователь держит палец на ячейке более 4 секунд (в этом примере), прежде чем поднимать его. – Anna

+105

Коррекция: он срабатывает несколько раз, чтобы указать различные состояния жестов (началось, изменено, закончено и т. Д.). Поэтому в методе обработчика проверьте свойство состояния распознавателя жестов, чтобы избежать действия в каждом состоянии жестов. Например: 'if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...'. – Anna

-2

Используйте метку времени свойство UITouch в touchesBegan, чтобы запустить таймер или остановить его, когда touchesEnded был уволен

+0

Спасибо за ваш ответ, но как я могу определить, какая строка касается касания? – foOg

+0

Возможно, я ошибаюсь, но ничего не предоставляется, чтобы помочь вам в этом. Вам нужно будет получить индексы текущих видимых ячеек с помощью [tableView indexPathsForVisibleRows], а затем, используя некоторые вычисления (смещение tableView сверху + X раз строк), вы будете знать, что координаты вашего пальца находятся на ряд. –

+0

Я уверен, что есть более простой способ сделать это, так или иначе, если у вас есть другая идея, я буду здесь :) – foOg

12

кажется более эффективным, чтобы добавить распознаватель непосредственно в камеру, как показано здесь:

Tap&Hold for TableView Cells, Then and Now

(прокрутка к примеру в нижней части)

+7

Как можно назначить новый объект распознавания жестов для каждой строки более эффективным, чем один распознаватель для всей таблицы? – user2393462435

+6

Помните, что существует только несколько ячеек, если dequeue работает правильно. – Ants

42

Я использовал Anna-Карениной ответ, и он работает почти отлично с очень серьезной ошибкой.

Если вы используете разделы, длительное нажатие на заголовок раздела приведет к неправильному результату нажатия первой строки в этом разделе, я добавил исправленную версию ниже (включая фильтрацию фиктивных вызовов на основе состояние жестов, по предложению Анны-Каренины).

- (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); 
      } 
     } 
    } 
} 
+0

Привет @marmor: Я хочу спросить, можно ли идентифицировать только часть вида, к которому пользователь прикасался? – Manthan

+0

Эй, вы можете использовать hitTest для этого (https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/instm/UIView/hitTest: withEvent :). Проверьте этот ответ, например, о том, как использовать: http://stackoverflow.com/a/2793253/819355 – marmor

+0

Хотя принятый ответ работает. Он регистрирует многократные пожары, а также ведет журнал при перетаскивании по экрану. Этот ответ не делает. Ответ на законную копию и вставку. Спасибо. – ChrisOSX

6

Я собрал небольшую категорию в 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, вы, вероятно, необходимо создать подкласс и соответствовать новому протоколу.

Это отлично работает для меня, надеюсь, что это поможет другим!

+0

отлично! удивительное использование категорий, спасибо – MaKo

+0

Удивительное использование шаблонов делегирования и категорий – valeCocoa

2

Просто добавьте UILongPressGestureRecognizer к данной ячейке прототипа в раскадровке, затем потяните жест в файл .m-файла viewController, чтобы создать метод действия. Я сделал это, как я уже сказал.

+0

Можете ли вы объяснить немного больше? Вы сделали прототип ячейки собственностью в вашем VC? –

16

Здесь поясняются инструкции, сочетающие ответ Песни Рассвета и ответ Мармора.

Перетащите длинный указатель распознавания жестов и поместите его в свою ячейку. Он переместится в нижнюю часть списка слева.

enter image description here

Затем подключите этот жест распознаватель так же, как вы бы подключить кнопку. enter image description here

Добавьте код из Мармора в обработчик действия

- (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

Лучший ответ на мой взгляд –

+3

Длинный указатель жестов печати следует применять к ячейке просмотра таблицы не таблицы. Отбрасывание его в ячейку таблицы будет иметь только прослушивание строки 0 при длительном нажатии. – Alex

9

Ответ в 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)") 
    } 

} 
8

Ответ в Swift 3.0 (Continuatuin ответа Рики в Swift)

Добавьте UIGestureRecognizerDelegate вашему ViewController

override func viewDidLoad() { 
    super.viewDidLoad() 

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

И функция:

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 == UIGestureRecognizerState.began) { 
     print("Long press on row, at \(indexPath!.row)") 
    } 
} 
0

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 
} 
Смежные вопросы