web-dev-qa-db-fra.com

UIButton dans une vue qui a un UITapGestureRecognizer

J'ai vue avec un UITapGestureRecognizer. Ainsi, lorsque je tape sur la vue, une autre vue apparaît au-dessus de cette vue. Cette nouvelle vue a trois boutons. Quand j'appuie maintenant sur l'un de ces boutons, je ne comprends pas l'action des boutons, mais uniquement l'action du toucher. Je ne peux donc plus utiliser ces boutons. Que puis-je faire pour que les événements passent par ces boutons? La chose étrange est que les boutons sont toujours mis en évidence.

Je ne peux pas simplement retirer le UITapGestureRecognizer après l'avoir reçu. Parce qu'avec cela, la nouvelle vue peut également être supprimée. Signifie que je veux un comportement similaire aux commandes vidéo plein écran.

177
V1ru8

Vous pouvez définir votre contrôleur ou votre vue (celui qui crée la reconnaissance des gestes) en tant que délégué du UITapGestureRecognizer. Ensuite, dans le délégué, vous pouvez implémenter -gestureRecognizer:shouldReceiveTouch:. Dans votre implémentation, vous pouvez tester si le contact appartient à votre nouvelle sous-vue et, le cas échéant, demander au programme de reconnaissance de gestes de l'ignorer. Quelque chose comme ce qui suit:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // test if our control subview is on-screen
    if (self.controlSubview.superview != nil) {
        if ([touch.view isDescendantOfView:self.controlSubview]) {
            // we touched our control surface
            return NO; // ignore the touch
        }
    }
    return YES; // handle the touch
}
250
Lily Ballard

Pour donner suite à la réponse de Kevin Ballard à Casey's:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
        if ([touch.view isKindOfClass:[UIControl class]]) {
            // we touched a button, slider, or other UIControl
            return NO; // ignore the touch
        }
    return YES; // handle the touch
}

Cela permet de faire fonctionner tous les types de commandes saisies par l'utilisateur, comme les boutons, les curseurs, etc.

155
cdasher

Trouvé cette réponse ici: link

Vous pouvez aussi utiliser

tapRecognizer.cancelsTouchesInView = NO;

Ce qui empêche le détecteur de taps d'être le seul à intercepter tous les taps

UPDATE - Michael a mentionné le lien vers la documentation décrivant cette propriété: cancelsTouchesInView

100
ejazz

Suite à la réponse de Kevin Ballard, j'ai eu le même problème et j'ai fini par utiliser ce code:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isKindOfClass:[UIButton class]]){
        return NO;
    }
    return YES;
}

Cela a le même effet mais cela fonctionnera sur n'importe quel UIButton à n'importe quelle profondeur de vue (mon UIButton avait plusieurs vues profondes et le délégué de UIGestureRecognizer n'en avait aucune référence.)

71
Casey

Dans iOS 6.0 et versions ultérieures, les actions de contrôle par défaut empêchent le comportement de reconnaissance de mouvements qui se chevauchent. Par exemple, l'action par défaut pour un bouton est une simple pression. Si un dispositif de reconnaissance de gestes unique est associé à la vue parent d’un bouton et que l’utilisateur appuie sur le bouton, la méthode d’action du bouton reçoit l’événement tactile à la place du dispositif de reconnaissance des gestes. Ceci ne s'applique qu'à la reconnaissance de geste qui chevauche l'action par défaut d'un contrôle, ce qui inclut: .....

extrait de la documentation API d'Apple

10
Jagie

Ces réponses étaient incomplètes. Je devais lire plusieurs posts sur la façon d'utiliser cette opération booléenne.

Dans votre fichier * .h, ajoutez ceci

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

Ajoutez ceci dans votre fichier * .m

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

    NSLog(@"went here ...");

    if ([touch.view isKindOfClass:[UIControl class]])
    {
        // we touched a button, slider, or other UIControl
        return NO; // ignore the touch
    }
    return YES; // handle the touch
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    //tap gestrure
    UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
    [tapGestRecog setNumberOfTapsRequired:1];
    [self.view addGestureRecognizer:tapGestRecog];


// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;

}


-(IBAction) screenTappedOnce
{
    NSLog(@"screenTappedOnce ...");

}
8
Sam B

J'ai trouvé un autre moyen de le faire à partir de ici . Il détecte le toucher, que ce soit à l'intérieur de chaque bouton ou non.

(1) pointInside: withEvent: (2) locationInView:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
       shouldReceiveTouch:(UITouch *)touch {
    // Don't recognize taps in the buttons
    return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
            ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
            ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}
7
MindMirror

Voici la Swift de réponse de Lily Ballard qui a fonctionné pour moi:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (scrollView.superview != nil) {
        if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
    }
    return true
}
3
John Riselvato

En optimisant la réponse de cdasher, vous obtenez

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
1
Clay Bridges

Si votre scénario est comme ça:

Vous avez une vue simple et certains boutons UIB, contrôles UITextField sont ajoutés en tant que sous-vues à cette vue. Maintenant, vous voulez fermer le clavier lorsque vous touchez n'importe où sur la vue, sauf sur les commandes (sous-vues que vous avez ajoutées)

Alors la solution est:

Ajoutez la méthode suivante à votre XYZViewController.m (qui a votre vue)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
1
NaveenRaghuveer

Vous pouvez empêcher le composant UITapGestureRecognizer d'annuler d'autres événements (tels que le toucher de votre bouton) en définissant la valeur booléenne suivante:

    [tapRecognizer setCancelsTouchesInView:NO];
1
Himanshu Mahajan