web-dev-qa-db-fra.com

UIView - "interaction utilisateur activée" false sur le parent mais vrai sur l'enfant?

Il semble que userInteractionEnabled = NO sur une vue parent empêche toute interaction de l'utilisateur sur toutes les sous-vues. Est-ce correct? Y a-t-il un moyen de contourner cela?

49
morgancodes

C'est exact, userInteractionEnabled défini sur NO dans une vue parent sera transmis en cascade à toutes les sous-vues. Si vous avez besoin d'interaction activée pour certaines sous-vues, mais pas pour d'autres, vous pouvez les séparer en deux vues parent: l'une avec userInteractionEnabled = YES et l'autre NON. Ensuite, placez ces deux vues parent dans la vue principale.

33
lazycs

Vous pouvez sous-classer UIView et remplacer hitTest: withEvent: de manière à transmettre des événements tactiles à une vue que vous spécifiez (_backView):

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];

    if (view == self) {
        view = _backView;
    }

    return view;
}

Si l'événement tactile devait être géré par cette vue, il serait passé à "_backView" (ce qui peut être un IBOutlet afin qu'il puisse être défini à l'aide du générateur d'interface); et si elle devait être gérée par une vue enfant, retournez-le simplement (résultat de [super hitTest:point withEvent:event];)

Cette solution est satisfaisante tant que vous savez quelle vue vous devez transmettre les événements; En outre, je ne sais pas s'il y a des problèmes car nous retournons une vue (_backView) qui n'est pas une sous-vue de la vue UIV actuelle! mais cela a bien fonctionné dans mon cas.

Une meilleure solution serait peut-être celle mentionnée dans Désactiver touche le fond de UIView afin que les boutons des vues inférieures soient cliquables Il est mentionné qu'il utilise -pointInside:withEvent:; Par rapport à la solution précédente, il est préférable de ne pas spécifier de '_backView' pour recevoir les événements (l'événement est simplement passé à la vue suivante dans la chaîne)! L’inconvénient est peut-être que nous devons exécuter -pointInside:withEvent: sur toutes les sous-vues (le temps système peut toutefois être négligeable)

15
Ali

Je viens de rencontrer une situation étrange. J'ai un UIView (appelez ceci, V), qui a un UIButton en tant que sous-vue. Appelez cette touche UIButton, le bouton X. Ci-dessous, la méthode que j'utilise pour la cible/sélecteur du bouton X. self est ci-dessous la vue V. Le paramètre de l'expéditeur est le bouton X. 

La situation qui me cause un problème est que si je touche un autre bouton de mon interface utilisateur (sur la barre de navigation, appelez ce bouton Y), puis très rapidement touche le bouton X, où l'action du bouton Y désactive l'affichage V, je reçois toujours le événement tactile envoyé au bouton X.

- (void) buttonAction: (UIButton *) sender
{
    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);

    // <snip>
}

Voici le résultat:

2014-12-19 16: 57: 53.826 MyApp [6161: 960615] vue d'ensemble: 0 
2014-12-19 16: 57: 53.826 Bouton MyApp [6161: 960615] lui-même: 1

C'est-à-dire que l'action du bouton s'est produite et que l'interaction de l'utilisateur a été désactivée dans la vue supérieure du bouton! Et la sous-vue avait toujours une interaction utilisateur activée!

Pour ceux d'entre vous qui pensent que cela semble artificiel, sur l'interface utilisateur de mon application fonctionnant sur un iPad (exécutant iOS 8.1.2), cela s'est produit par accident lors de mon utilisation de l'application. Ce n’était pas quelque chose que j’avais originellement essayé de générer.

Pensées?

Ma solution actuelle est indiquée ci-dessous, mais il semble vraiment étrange que ce soit nécessaire!

- (void) buttonAction: (id) sender
{
    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);
    if (! self.userInteractionEnabled) return;

    // <snip>
}
2
Chris Prince

J'ai inventé une solution étrange pour cela: j'avais une vue enfant dans une cellule tableView que je voulais toucher, mais le parent n'aurait pas dû ...

Aucune des solutions ci-dessus n'a fonctionné pour moi, mais j'ai trouvé une autre solution. Accédez au storyboard et ajoutez un tapGestureRecognizer à la vue parent pour absorber les retouches sur la vue parent. Problème résolu!

0
Alfi

Je fais cela dans un xib qui est ma vue "contrôleur d'alerte personnalisé".

for (UIView *subview in self.superview.subviews) {

    if (![subview isEqual:self]) {
        subview.userInteractionEnabled = NO;
    }
}
0
NeoGER89