221 votes

UITapGestureRecognizer casse UITableView didSelectRowAtIndexPath

J'ai écrit ma propre fonction pour faire défiler les champs de texte vers le haut lorsque le clavier s'affiche. Afin d'écarter le clavier en tapant à l'écart du champ de texte, j'ai créé une fonction UITapGestureRecognizer qui prend en charge la démission du premier répondant sur le champ de texte lorsque l'on tape ailleurs.

Maintenant, j'ai également créé un autocomplétion pour le champ de texte qui crée une UITableView juste en dessous du champ de texte et le remplit d'éléments au fur et à mesure que l'utilisateur saisit du texte.

Cependant, lorsque l'on sélectionne l'une des entrées du tableau complété automatiquement, didSelectRowAtIndexPath n'est pas appelé. Au lieu de cela, il semble que la reconnaissance des gestes de tapotement soit appelée et qu'elle abandonne simplement le premier répondant.

Je suppose qu'il existe un moyen d'indiquer à l'outil de reconnaissance des gestes d'effleurement qu'il doit continuer à transmettre le message d'effleurement à l'unité de traitement de l'information. UITableView mais je n'arrive pas à savoir ce que c'est. Toute aide serait très appréciée.

0 votes

Voir ce fil .

271voto

Jason Points 891

Ok, j'ai finalement trouvé après quelques recherches dans la documentation de la reconnaissance des gestes.

La solution a consisté à mettre en œuvre UIGestureRecognizerDelegate et ajoutez ce qui suit :

#pragma mark UIGestureRecognizerDelegate methods

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
  if ([touch.view isDescendantOfView:autocompleteTableView]) {

    // Don't let selections of auto-complete entries fire the 
    // gesture recognizer
    return NO;
  }

  return YES;
}

C'est réglé. J'espère que cela aidera d'autres personnes.

0 votes

Vous devez aussi probablement sauter les tapotements sur le champ de texte.

5 votes

J'ai eu plus de chance avec return ![touch.view isKindOfClass:[UITableViewCell class]];

1 votes

@Josh Cela ne fonctionne pas si vous tapez sur les étiquettes à l'intérieur de la cellule. En fait, la réponse de Jason est parfaite pour ce dont j'ai besoin.

225voto

TMilligan Points 1028

La façon la plus simple de résoudre ce problème est de:

UITapGestureRecognizer *tapRec = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(tap:)];
[tapRec setCancelsTouchesInView:NO];

Cela permet à l'UIGestureRecognizer reconnaître le robinet et aussi passer le toucher pour le prochain intervenant. Une conséquence inattendue de cette méthode est que si vous avez un UITableViewCell sur l'écran qui pousse un autre point de vue contrôleur. Si l'utilisateur appuie sur la ligne pour fermer le clavier, à la fois le clavier et la poussée sera reconnu. Je doute que cela soit ce que vous souhaitez, mais cette méthode est adéquate pour de nombreuses situations.

Aussi, l'expansion sur Robert réponse, si vous avez un pointeur vers la tableview en question, alors vous pouvez comparer directement sa classe au lieu d'avoir à les convertir à une chaîne, et à espérer qu'Apple ne change pas la nomenclature:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
     shouldReceiveTouch:(UITouch *)touch
{
    if([touch.view class] == tableview.class){
        return //YES/NO
    }

    return //YES/NO

}

Rappelez-vous, vous devez également déclarer l'UIGestureRecognizer d'avoir un délégué du présent code.

5 votes

Merci, setCancelsTouchesInView change tout :)

0 votes

Vous pouvez toujours utiliser isDescendantOfView au lieu de simplement vérifier si le class est égal, puisque vous pouvez taper sur une sous-vue. Cela dépend de ce dont vous avez besoin.

0 votes

La seule chose qui a fonctionné :)

14voto

Robert Altman Points 2535

Une solution similaire consiste à mettre en œuvre gestureRecognizer:shouldReceiveTouch: en utilisant la classe de la vue pour déterminer l'action à entreprendre. Cette approche a l'avantage de ne pas masquer les taps dans la région entourant directement la table (les vues de cette région descendent toujours des instances UITableView, mais elles ne représentent pas des cellules).

Cette méthode présente également l'avantage de fonctionner avec plusieurs tableaux sur une seule vue (sans ajouter de code supplémentaire).

Attention : on suppose qu'Apple ne changera pas le nom de la classe.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ![NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"];
}

1 votes

Pour éliminer la chaîne de caractères du nom de la classe, utilisez cette ligne return ![[touch.view.superview class] isSubclassOfClass:[UITableViewCell class]];

0voto

bgfriend0 Points 767

Voici ma solution, qui lie directement le paramètre shouldReceiveTouch du recognizer au fait que le clavier soit affiché ou non.

Dans votre délégué de reconnaissance des gestes du robinet :

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([PFXKeyboardStateListener sharedInstance].visible) {
        return YES;
    }

    return NO;
}

Et le PFXKeyboardStateListener.h :

@interface PFXKeyboardStateListener : NSObject
{
    BOOL _isVisible;
}

+ (PFXKeyboardStateListener *)sharedInstance;

@property (nonatomic, readonly, getter=isVisible) BOOL visible;

@end

Et le PFXKeyboardStateListener.m :

static PFXKeyboardStateListener *sharedInstance;

@implementation PFXKeyboardStateListener

+ (PFXKeyboardStateListener *)sharedInstance
{
    return sharedInstance;
}

+ (void)load
{
    @autoreleasepool {
        sharedInstance = [[self alloc] init];
    }
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (BOOL)isVisible
{
    return _isVisible;
}

- (void)didShow
{
    _isVisible = YES;
}

- (void)didHide
{
    _isVisible = NO;
}

- (id)init
{
    if ((self = [super init])) {
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(didShow) name:UIKeyboardDidShowNotification object:nil];
        [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil];
    }
    return self;
}

@end

Vous pouvez mettre à jour le modèle singleton de l'écouteur de clavier, je ne l'ai pas encore fait. J'espère que cela fonctionne pour tous les autres aussi bien que pour moi. ^^

0voto

cxa Points 2760

Implémentez cette méthode pour le délégué de UIGestureRecognizer :

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
{
  UIView *superview = touch.view;
  do {
    superview = superview.superview;
    if ([superview isKindOfClass:[UITableViewCell class]])
      return NO;
  } while (superview && ![superview isKindOfClass:[UITableView class]]);

  return superview != nil;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X