2010-10-13 12 views
165

Mi piacerebbe gestire una pressione prolungata su un UITableViewCell per stampare un "menu di accesso rapido". Qualcuno lo ha già fatto?Premere a lungo su UITableView

In particolare il gesto riconosce su UITableView?

risposta

403

Prima aggiungere alla lunga stampa gesto riconoscitore alla vista tabella:

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

Poi nel gestore gesto :

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

bisogna stare attenti con questo in modo che non interferisca con il normale spillatura dell'utente del cellulare e anche notare t il cappello handleLongPress potrebbe sparare più volte (ciò è dovuto al cambio di stato del gesture di riconoscimento).

+1

Fantastico !!! Molte grazie! Ma un'ultima piccola domanda: perché il metodo handleLongPress è chiamato quando il tocco termina ??? – foOg

+0

Non viene chiamato quando il tocco finisce ma può sparare più volte se l'utente tiene il dito sulla cella per più di 4 secondi (in questo esempio) prima di sollevarlo. Correzione – Anna

+105

: scocca più volte per indicare i diversi stati del gesto (iniziato, modificato, terminato, ecc.). Quindi, nel metodo del gestore, controlla la proprietà di stato del riconoscitore di gesti per evitare di eseguire l'azione in ogni stato del gesto. Ad esempio: 'if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...'. – Anna

-2

Utilizzare la proprietà timestamp UITouch in touchesBegan per lanciare un timer o fermarlo quando touchesEnded stato licenziato

+0

Grazie per la risposta, ma come posso rilevare quale riga è interessata dal tocco? – foOg

+0

Potrei sbagliarmi, ma non viene fornito nulla per aiutarti a farlo. Dovrai ottenere gli indici delle celle visibili attuali con [tableView indexPathsForVisibleRows] e poi, usando alcuni calcoli (il tuo offset TableView dall'alto + X volte le righe) saprai che le coordinate del tuo dito sono su cui riga. –

+0

Sono sicuro che c'è un modo più semplice per farlo, comunque se hai un'altra idea, sarò qui :) – foOg

12

sembra essere più efficiente di aggiungere il sistema di riconoscimento direttamente alla cella come illustrato di seguito:

Tap&Hold for TableView Cells, Then and Now

(scorrere fino alla esempio in basso)

+7

In che modo l'assegnazione di un nuovo oggetto riconoscitore di gesti per ogni riga può essere più efficiente di un singolo riconoscimento per l'intera tabella? – user2393462435

+6

Ricorda che ci sono solo poche celle create se dequeue funziona correttamente. – Ants

42

ho usato di Anna-Karenina risposta, e funziona quasi alla grande con un bug molto serio.

Se si utilizzano le sezioni, premendo a lungo il titolo della sezione si otterrà un risultato errato premendo la prima riga in quella sezione, ho aggiunto una versione fissa di seguito (incluso il filtraggio delle chiamate fittizie basato sul stato dei gesti, secondo il suggerimento di 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); 
      } 
     } 
    } 
} 
+0

Ciao @marmor: voglio chiedere che è possibile identificare solo una parte di una vista che l'utente ha toccato? – Manthan

+0

Ehi, puoi usare hitTest per questo (https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/instm/UIView/hitTest: withEvent :). Controlla questa risposta per esempio su come usare: http://stackoverflow.com/a/2793253/819355 – marmor

+0

Mentre la risposta accettata funziona. Registra più incendi, insieme alla registrazione mentre si trascina sullo schermo. Questa risposta non lo fa. Una risposta legittima copia e incolla. Grazie. – ChrisOSX

6

Ho messo insieme una piccola categoria su UITableView basata sull'eccellente risposta di Anna Karenina.

In questo modo avrete a disposizione un metodo di delega conveniente come quello che siete abituati a gestire le normali visualizzazioni di tabelle. Check it out:

// 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]; 
     } 
    } 
} 

Se si desidera utilizzare questo in un UITableViewController, probabilmente è necessario sottoclasse e conforme al nuovo protocollo.

Funziona benissimo per me, spero che aiuti gli altri!

+0

fantastico! uso fantastico delle categorie, grazie – MaKo

+0

Incredibile utilizzo di modelli di delega e categorie – valeCocoa

2

Basta aggiungere UILongPressGestureRecognizer alla cella prototipo specificata nello storyboard, quindi tirare il gesto sul file .m di viewController per creare un metodo di azione. L'ho fatto come ho detto.

+0

Puoi spiegarci un po 'di più? Hai reso la cella prototipo una proprietà nel tuo VC? –

16

Ecco le istruzioni chiarite che combinano la risposta di Dawn Song e la risposta di Marmor.

Trascinare una lunga pressione Gesture Recognizer e rilasciarla nella cella della tabella. Salterà in fondo alla lista a sinistra.

enter image description here

Collegare quindi il sistema di riconoscimento gesto allo stesso modo in cui si collegare un pulsante. enter image description here

Aggiungere il codice Marmor nel gestore all'azione

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

La risposta migliore a mio parere –

+3

Il Riconoscitore di gesti a pressione lunga deve essere applicato alla vista tabella e non alla cella di visualizzazione tabella. Lasciarlo nella cella di visualizzazione tabella avrà solo la riga 0 in ascolto a premere a lungo. – Alex

9

risposta a Swift:

Aggiungi delegato UIGestureRecognizerDelegate al vostro UITableViewController.

Entro 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) 

} 

E la funzione:

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

risposta a Swift 3.0 (Continuatuin della risposta di Ricky a Swift)

Aggiungere il UIGestureRecognizerDelegate al 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) 
} 

E la funzione:

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 risposta, utilizzando la sintassi moderna, incorporando altre risposte, ed eliminando il codice non necessario.

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 
} 
Problemi correlati