Je voudrais gérer un appui long sur a UITableViewCell
pour imprimer un "menu d'accès rapide". Est-ce que quelqu'un a déjà fait ça?
Particulièrement le geste reconnaît-il UITableView
?
Réponses:
Ajoutez d'abord le module de reconnaissance des gestes de pression longue à la vue de tableau:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:@selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];
Puis dans le gestionnaire de gestes:
-(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);
}
}
Vous devez faire attention à cela afin que cela n'interfère pas avec le tapotement normal de l'utilisateur sur la cellule et notez également que cela handleLongPress
peut se déclencher plusieurs fois (cela sera dû aux changements d'état de la reconnaissance de mouvement).
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) ...
.
UITableView
, pas au UITableViewCell
...)
J'ai utilisé la réponse d'Anna-Karenina, et cela fonctionne presque très bien avec un bug très sérieux.
Si vous utilisez des sections, appuyer longuement sur le titre de la section vous donnera un mauvais résultat en appuyant sur la première ligne de cette section, j'ai ajouté une version fixe ci-dessous (y compris le filtrage des appels factices en fonction de l'état du geste, par Suggestion d'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);
}
}
}
}
Réponse dans Swift 5 (Suite de la réponse de Ricky dans Swift)
Ajoutez le
UIGestureRecognizerDelegate
à votre ViewController
override func viewDidLoad() {
super.viewDidLoad()
//Long Press
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
longPressGesture.minimumPressDuration = 0.5
self.tableView.addGestureRecognizer(longPressGesture)
}
Et la fonction:
@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)")
}
}
Voici des instructions clarifiées combinant la réponse de Dawn Song et la réponse de Marmor.
Faites glisser un outil de reconnaissance de gestes et déposez-le dans votre cellule de tableau. Il sautera au bas de la liste sur la gauche.
Connectez ensuite le module de reconnaissance de gestes de la même manière que vous connectez un bouton.
Ajoutez le code de Marmor dans le gestionnaire d'action
- (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);
}
}
}
}
Il semble plus efficace d'ajouter le module de reconnaissance directement à la cellule, comme indiqué ici:
Appuyez et maintenez pour les cellules TableView, hier et maintenant
(faites défiler jusqu'à l'exemple en bas)
Réponse dans Swift:
Ajoutez un délégué UIGestureRecognizerDelegate
à votre UITableViewController.
Dans 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)
}
Et la fonction:
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)")
}
}
J'ai rassemblé une petite catégorie sur UITableView basée sur l'excellente réponse d'Anna Karenina.
Ainsi, vous aurez une méthode de délégué pratique, comme vous en avez l'habitude lorsque vous traitez avec des vues de table normales. Vérifiez-le:
// 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];
}
}
}
Si vous souhaitez l'utiliser dans un UITableViewController, vous devez probablement sous-classer et vous conformer au nouveau protocole.
Cela fonctionne très bien pour moi, j'espère que cela aidera les autres!
Réponse Swift 3, utilisant une syntaxe moderne, incorporant d'autres réponses et éliminant le code inutile.
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
}
Ajoutez simplement UILongPressGestureRecognizer à la cellule prototype donnée dans le storyboard, puis tirez le geste vers le fichier .m de viewController pour créer une méthode d'action. Je l'ai fait comme je l'ai dit.
Utilisez la propriété d'horodatage UITouch dans touchesBegan pour lancer un minuteur ou l'arrêter lorsque touchEnded a été déclenché