Pouvez-vous attacher un UIGestureRecognizer à plusieurs vues?

228
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)];
[self.view1 addGestureRecognizer:tapGesture];
[self.view2 addGestureRecognizer:tapGesture];
[tapGesture release];

Dans le code ci-dessus, seuls les appuis sur view2sont reconnus. Si je commente la troisième ligne, les tapotements sur view1sont reconnus. Si j'ai raison et que vous ne pouvez utiliser qu'une seule fois un identificateur de mouvement, je ne sais pas s'il s'agit d'un bogue ou s'il a juste besoin de plus de documentation.

kubi
la source

Réponses:

334

A UIGestureRecognizerdoit être utilisé avec une seule vue. Je suis d'accord que la documentation est inégale. Qui UIGestureRecognizera une seule viewpropriété le révèle:

vue

La vue à laquelle le reconnaisseur de gestes est attaché. (lecture seulement)

@property (nonatomique, en lecture seule) UIView * view

Discussion Vous attachez (ou ajoutez) un identificateur de mouvement à un objet UIView à l'aide de la méthode addGestureRecognizer :.

TomSwift
la source
11
Parce que l'ajout d'un identificateur de mouvement à une vue se produit au moment de l'exécution (par rapport à la compilation).
TomSwift
1
J'ai compris, mais tout comme la détection de dire que nous n'avons pas utilisé de variable, XCode pourrait dire sur la base du code que nous avons passé le même reconnaisseur à plusieurs vues et pourrait avertir le codeur.
Zoltán Matók
1
L'avertissement du compilateur à propos de plusieurs vues affectant le même UITapGestureRecognizer est un non-sens, car vous pouvez le faire exprès, par exemple si vous souhaitez déplacer le reconnaisseur de mouvement de prise d'une vue à une autre. Cela dit, c'est une limitation stupide que la reconnaissance des gestes ne peut pas être utilisée sur plusieurs vues.
Erik van der Neut
1
iOS 9 applique désormais une seule vue par reconnaissance de gestes, j'avais utilisé la méthode de création d'interface ci-dessous, mais maintenant je reçois le message suivant lorsque j'essaie de l'utiliser (certains détails ont été raccourcis): AVERTISSEMENT: une reconnaissance de gestes (< UITapGestureRecognizer: .....>) a été configuré dans un storyboard / xib pour être ajouté à plusieurs vues (-> <UIView:; frame = (0 44; 600 536); autoresize = RM + BM; gestureRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) à la fois, cela n'a jamais été autorisé et est désormais appliqué. À partir d'iOS 9.0, il sera placé dans la première vue dans laquelle il sera chargé.
George Brown
Si vous ajoutez à la vue pour la deuxième fois, la vue a été attachée auparavant par ce module de reconnaissance qui se détache automatiquement. UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];La vue de sortie1 n'a pas de tableau de reconnaissance de mouvements; view2 a un tableau de reconnaissance des gestes
kokos8998
48

Je l'ai contourné en utilisant ce qui suit.

for (UIButton *aButton in myButtons) {

            UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
            longPress.minimumPressDuration=1.0;
            [aButton addGestureRecognizer:longPress];
            [longPress release];

}

Ensuite, dans ma méthode handleLongPress, je viens de définir un UIButton égal à la vue de la reconnaissance des gestes et branchez ce que je fais en fonction de ce bouton

- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        UIButton *whichButton=(UIButton *)[gesture view];
        selectedButton=(UIButton *)[gesture view];
    ....
}
kwalker
la source
1
Excellente réponse, merci une tonne. Cela aurait pu être la réponse acceptée si la question était "Comment attacher un UIGestureRecognizer à plusieurs vues?"
D_D
7
Cela (ou quelque chose de très proche) n'a pas fonctionné pour moi. J'ai ajouté plusieurs vues à un outil de reconnaissance des gestes tactiles dans Interface Builder et j'ai connecté l'outil de reconnaissance à une action. L'action était appelée à chaque fois qu'une vue attachée était tapée, mais gesture.view était toujours la dernière vue attachée.
Aneil Mallavarapu
C'est une réponse vraiment sympa et aussi très utile et d'accord avec @MicRO +1
Dilip
2
Aneil, c'est parce que vous n'avez pas créé de nouvelles instances de la reconnaissance des gestes. Ce qui se passe dans la boucle dans cette réponse ici, c'est que de nouvelles instances de reconnaissance de gestes sont créées, chacune avec une seule vue attachée. Ils peuvent tous pointer vers le même gestionnaire, où vous vérifiez ensuite la vue pour voir laquelle a été touchée.
Erik van der Neut
1
Quelqu'un d'autre peut-il confirmer que cela ne fonctionne plus dans la version actuelle d'Obj-C / Swift?
Maxi Mus
18

Pour Swift 3 au cas où quelqu'un l'exigerait: Basé sur la réponse de Bhavik Rathod ci-dessus.

 func setGestureRecognizer() -> UIPanGestureRecognizer {

        var panRecognizer = UIPanGestureRecognizer()

        panRecognizer = UIPanGestureRecognizer (target: self, action: #selector(pan(panGesture:)))
        panRecognizer.minimumNumberOfTouches = 1
        panRecognizer.maximumNumberOfTouches = 1
        return panRecognizer
    }

        ///set the recognize in multiple views
        view1.addGestureRecognizer(setGestureRecognizer())
        view2.addGestureRecognizer(setGestureRecognizer())
George Asda
la source
3
c'est essentiellement créer plusieurs gestes pour les deux vues, toujours la même règle: chaque geste n'a qu'une seule vue à laquelle être attaché
Abdoelrhman
3
Non, la fonction crée un geste chaque fois qu'elle est appelée
Abdoelrhman
2
le nom de la fonction est incorrect. la fonction logique ici est une fonction d'obtention. il faut donc le nommer: getGestureRecognizeparce que c'est ce que fait cette fonction
David Seek
Travaillez bien pour moi! Et code plus propre que de créer plusieurs variables ou de mettre du code entier pour la création dans addGestureRecognizer
Codenator81
11

Nous pouvons faire quelque chose comme ça, c'est facile et simple

1) créer une fonction comme ci-dessous dans votre contrôleur (cette fonction renverra GestureRecognizer)

-(UITapGestureRecognizer*)setRecognizer{
     UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openProfile)];
     [gestureRecognizer setNumberOfTapsRequired:1];
     return gestureRecognizer;
}

2) définissez maintenant ce module de reconnaissance dans plusieurs vues

[self.view1 addGestureRecognizer:[self setRecognizer]]; 
[self.view2 addGestureRecognizer:[self setRecognizer]];
Bhavik Rathod
la source
Cela ne fonctionne pas pour moi lorsque j'utilise deux étiquettes au lieu de vues.
Mihir Oza
3
@Mihir Oza, cela ne peut pas fonctionner directement pour UILabels. En raison des étiquettes, cela n'a aucun sens pour l'interaction avec l'utilisateur. Si vous souhaitez ajouter des mouvements pour UILabels, ajoutez cette ligne unique labelName..isUserInteractionEnabled = true dans Swift. Ajoutez ensuite des gestes.
iOS
Il est trop tard, j'ai déjà corrigé ça. Mais merci pour la suggestion. Votre commentaire sera utile aux utilisateurs de la pile. Apprécié!
Mihir Oza
1
Je suppose que la ligne setNumberOfTapsRequired:1n'est pas nécessaire
Naveed Abbas
9

Non, vous ne devez pas attacher de reconnaissance de gestes à plusieurs vues.

Il y a ces informations explicites dans la documentation Apple:

Les reconnaisseurs de gestes sont attachés à une vue

Chaque reconnaissance de gestes est associée à une vue. En revanche, une vue peut avoir plusieurs reconnaisseurs de gestes, car une seule vue peut répondre à de nombreux gestes différents. Pour qu'un outil de reconnaissance de gestes reconnaisse les touches qui se produisent dans une vue particulière, vous devez attacher l'outil de reconnaissance de gestes à cette vue.

Guide de gestion des événements pour iOS - Gesture Recognizers Apple Developer Library

Alors que d'autres mentionnent qu'ils pourraient fonctionner dans certains cas, cela est clairement contraire à la documentation et pourrait changer dans n'importe quelle future version d'iOS.

Ce que vous pouvez faire, c'est ajouter des reconnaisseurs de gestes distincts aux vues que vous souhaitez surveiller et ils peuvent partager une action commune.

Joseph Lord
la source
4

Eh bien, si quelqu'un ne veut pas coder pour ajouter une vue gestuelle pour plusieurs boutons, comme kwalker a répondu ci-dessus, et souhaite le faire via Interface Builder, cela peut vous aider.

1) Vous pouvez ajouter la reconnaissance des gestes de pression longue à partir de la bibliothèque d'objets comme vous ajoutez d'autres objets comme les boutons UIB et les étiquettes UIL.

entrez la description de l'image ici Au départ, ce que j'ai fini par utiliser, c'est que je n'en ai pris qu'un

2) Définissez les sorties de référence UIButtonet les actions envoyées avec le propriétaire du fichier.

entrez la description de l'image ici

Remarque: Si vous avez plusieurs UIButton ou tout autre objet, vous aurez besoin d'un identificateur de gestes distinct pour chacun d'eux. Pour plus de détails, veuillez vous référer à ma question. Se tromper de balise UIButton sur le reconnaisseur de gestes de pression longue

rohan-patel
la source
Il est très facile de lier plus d'un UIView au reconnaisseur d'invité en utilisant IB. La question portait sur la génération de code.
AlexeyVMP
3

si vous avez une vue fixe, je vous suggère de faire quelque chose comme ça

[self.view1 addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)]];
[self.view2 addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)]];

de cette façon réduira plusieurs variables inutiles différentes

Raynaldio Limarga
la source
3

Vous pouvez créer une extension générique en vue pour ajouter facilement des reconnaisseurs de gestes. Ceci est juste un exemple mais cela pourrait ressembler à ceci

extension UIView {

    func setGestureRecognizer<Gesture: UIGestureRecognizer>(of type: Gesture.Type, target: Any, actionSelector: Selector, swipeDirection: UISwipeGestureRecognizer.Direction? = nil, numOfTaps: Int = 1) {
    let getRecognizer = type.init(target: target, action: actionSelector)

    switch getRecognizer {
    case let swipeGesture as UISwipeGestureRecognizer:
        guard let direction = swipeDirection else { return }
        swipeGesture.direction = direction
        self.addGestureRecognizer(swipeGesture)
    case let tapGesture as UITapGestureRecognizer:
        tapGesture.numberOfTapsRequired = numOfTaps
        self.addGestureRecognizer(tapGesture)
    default:
        self.addGestureRecognizer(getRecognizer)
    }
  }

}

Pour ajouter un module de reconnaissance à 2 touches sur une vue, vous devez simplement appeler:

let actionSelector = #selector(actionToExecute)
view.setGestureRecognizer(of: UITapGestureRecognizer.self, target: self, actionSelector: actionSelector, numOfTaps: 2)

Vous pouvez également ajouter facilement un identificateur de balayage

view.setGestureRecognizer(of: UISwipeGestureRecognizer.self, target: self, actionSelector: actionSelector, swipeDirection: .down)

etc. N'oubliez pas que la cible doit être liée au sélecteur.

Martin
la source
2

Remplacer la classe par ' <UIScrollViewDelegate>'

Et utilisez cette méthode dans la classe .m:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

Cette méthode vous aidera à activer plusieurs balayages sur une seule vue.

AnkitRox
la source
2

Qu'en est-il de réécrire (recréer) votre GestureRecognize chaque fois que vous ajoutez un identificateur de geste pointant vers la même fonction. Dans le cas ci-dessous, cela fonctionne. J'utilise IBOutletCollection

Swift 2:

@IBOutlet var topicView: [UIView]!

override func viewDidLoad() {
        for view in self.topicView as [UIView] {
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "viewClicked:"))
    }
}

func viewClicked(recognizer: UITapGestureRecognizer) {
    print("tap")
}
febaisi
la source
-6

Vous pouvez le faire en utilisant ce code mes vues qui sont des vues d'image dans le xib.

- (void)viewDidLoad
{
    firstIV.tag = 501;
    secondIV.tag = 502;
    thirdIV.tag = 503;
    forthIV.tag = 504;

    [self addTapGesturetoImageView: firstIV];
    [self addTapGesturetoImageView: secondIV];
    [self addTapGesturetoImageView: thirdIV];
    [self addTapGesturetoImageView: forthIV];
}

-(void)addTapGesturetoImageView:(UIImageView*)iv
{
    iv.userInteractionEnabled = YES;
    UITapGestureRecognizer * textfielBGIVTapGasture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textfielBGIVTapped:)];
    textfielBGIVTapGasture.numberOfTapsRequired = 1;
    [iv addGestureRecognizer:textfielBGIVTapGasture];
}

- (void)textfielBGIVTapped:(UITapGestureRecognizer *)recognizer {
    int tag = recognizer.view.tag-500;
    switch (tag) {
        case 1:
        {
            //firstIV tapped;
            break;
        }
        case 2:
        {
            //secondIV tapped;
            break;
        }
        case 3:
        {
            //thirdIV tapped;
            break;
        }
        case 4:
        {
            //forthIV tapped;
            break;
        }
        default: {
            break;
        }
    }
}
Dilip
la source
1
Vous créez plusieurs reconnaisseurs de gestes; ma question initiale était de réutiliser un seul identificateur de geste, ce que vous ne pouvez pas faire.
kubi
1
Quel est l'intérêt d'ajouter 500à toutes les balises de vos vues, puis de soustraire 500? Pourquoi ne pas simplement commencer vos tags à 1(ou même 0) au lieu de 501?
ma11hew28
@MattDiPasquale, Peu importe si vous voulez commencer avec le 1son, j'ai copié ce code depuis mon application d'où je le donne 501. Mais oui, ne donnez pas à 0bcoz que j'ai lu quelque part que cela indique toujours la vue des parents, donc cela créera des complications, croyez-moi, je l'ai fait face.
Dilip
Le texte clé de la documentation est «La vue établit une référence forte au reconnaisseur de gestes». ce qui signifie que la vue est propriétaire du geste. Le geste ne peut avoir qu'un seul propriétaire. Voir le lien
Phantom59