Können Sie einen UIGestureRecognizer an mehrere Ansichten anhängen?


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

Im obigen Code werden nur Anschläge view2erkannt. Wenn ich die dritte Zeile auskommentiere, view1werden Abgriffe erkannt. Wenn ich recht habe und Sie einen Gestenerkenner nur einmal verwenden können, bin ich mir nicht sicher, ob dies ein Fehler ist oder nur weitere Dokumentation benötigt.

Antworten:


334

A UIGestureRecognizersoll mit einer einzigen Ansicht verwendet werden. Ich bin damit einverstanden, dass die Dokumentation fleckig ist. Das UIGestureRecognizerhat eine einzige viewEigenschaft verrät es:

Aussicht

Die Ansicht, an die der Gestenerkenner angehängt ist. (schreibgeschützt)

@property (nichtatomar, schreibgeschützt) UIView * -Ansicht

Diskussion Sie hängen einen Gestenerkenner mit der Methode addGestureRecognizer: an ein UIView-Objekt an (oder fügen ihn hinzu).


11
Weil das Hinzufügen eines Gestenerkenners zu einer Ansicht zur Laufzeit (im Vergleich zur Kompilierungszeit) erfolgt.
TomSwift

1
Ich habe das verstanden, aber ähnlich wie beim Erkennen, dass wir keine Variable verwendet haben, konnte XCode anhand des Codes erkennen, dass wir denselben Erkenner an mehrere Ansichten übergeben haben, und den Codierer warnen.
Zoltán Matók

1
Die Compiler-Warnung über mehrere Ansichten, die denselben UITapGestureRecognizer zuweisen, ist Unsinn, da Sie dies möglicherweise absichtlich tun möchten, z. B. wenn Sie den Tap-Gestenerkenner von einer Ansicht in eine andere verschieben möchten. Es ist jedoch eine dumme Einschränkung, dass der Gestenerkenner nicht für mehrere Ansichten verwendet werden kann.
Erik van der Neut

1
iOS 9 erzwingt jetzt eine einzelne Ansicht pro Gestenerkennung. Ich habe die unten stehende Methode zur Erstellung von Schnittstellen verwendet, aber jetzt wird die folgende Meldung angezeigt, wenn ich versuche, sie zu verwenden (einige Details wurden der Kürze halber abgeschnitten): WARNUNG: Eine Gestenerkennung (<) UITapGestureRecognizer: .....>) wurde in einem Storyboard / xib eingerichtet, um mehr als einer Ansicht hinzugefügt zu werden (-> <UIView :; frame = (0 44; 600 536); autoresize = RM + BM; gestureRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) zu einem Zeitpunkt war dies nie erlaubt und wird jetzt erzwungen. Ab iOS 9.0 wird es in die erste Ansicht gestellt, in die es geladen wird.
George Brown

Wenn Sie die Ansicht zum zweiten Mal hinzufügen, wurde die Ansicht angehängt, bevor dieser Erkenner automatisch getrennt wird. UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];Die Ausgabeansicht1 verfügt über kein Gestenerkennungsarray. view2 hat ein Gestenerkennungs-Array
kokos8998

48

Ich habe es umgangen, indem ich das Folgende verwendet habe.

for (UIButton *aButton in myButtons) {

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

}

Dann habe ich in meiner handleLongPress-Methode einfach einen UIButton gesetzt, der der Ansicht des Gestenerkenners entspricht, und verzweige, was ich basierend auf dieser Schaltfläche mache

- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        UIButton *whichButton=(UIButton *)[gesture view];
        selectedButton=(UIButton *)[gesture view];
    ....
}

1
Tolle Antwort. Vielen Dank. Dies könnte die akzeptierte Antwort gewesen sein, wenn die Frage "Wie Sie einen UIGestureRecognizer an mehrere Ansichten anhängen?" Lautete.
D_D

7
Dies (oder etwas sehr Nahes) hat bei mir nicht funktioniert. Ich habe einem Tippengestenerkenner in Interface Builder mehrere Ansichten hinzugefügt und den Erkenner mit einer Aktion verbunden. Die Aktion wurde immer dann aufgerufen, wenn auf eine angehängte Ansicht getippt wurde, aber gesture.view war immer die letzte angehängte Ansicht.
Aneil Mallavarapu

Dies ist eine sehr schöne Antwort und auch sehr hilfreich und stimmt mit @MicRO +1
Dilip

2
Aneil, das liegt daran, dass Sie keine neuen Instanzen des Gestenerkenners erstellt haben. In dieser Antwort geschieht in der Schleife, dass neue Instanzen von Gestenerkennern erstellt werden, denen jeweils nur eine Ansicht zugeordnet ist. Sie können alle auf denselben Handler zeigen, wo Sie dann die Ansicht überprüfen, um festzustellen, welcher berührt wurde.
Erik van der Neut

1
Kann jemand anderes bestätigen, dass dies in der aktuellen Version von Obj-C / Swift nicht mehr funktioniert?
Maxi Mus

18

Für Swift 3, falls jemand dies benötigt: Basierend auf der obigen Antwort von Bhavik Rathod.

 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())

3
Das bedeutet im Grunde, dass mehrere Gesten für die beiden Ansichten erstellt werden, immer noch dieselbe Regel: Jede Geste hat nur eine Ansicht, an die sie angehängt werden kann
Abdoelrhman

3
Nein, die Funktion erstellt jedes Mal eine Geste, wenn sie aufgerufen wird
Abdoelrhman

2
Der Name der Funktion ist falsch. Die logische Funktion hier ist eine Abruffunktion. so sollte es genannt werden: getGestureRecognizeweil das ist, was diese Funktion tut
David Seek

Arbeite gut für mich! Und Code sauberer als mehrere Variablen zu erstellen oder ganzen Code für die Erstellung in addGestureRecognizer
Codenator81

11

Wir können so etwas tun, es ist einfach und unkompliziert

1) Erstellen Sie eine Funktion wie unten in Ihrem Controller (diese Funktion gibt GestureRecognizer zurück).

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

2) Stellen Sie diesen Erkenner nun in mehreren Ansichten ein

[self.view1 addGestureRecognizer:[self setRecognizer]]; 
[self.view2 addGestureRecognizer:[self setRecognizer]];

Es funktioniert bei mir nicht, wenn ich zwei Beschriftungen anstelle von Ansichten verwende.
Mihir Oza

3
@Mihir Oza, es kann nicht direkt für UILabels funktionieren. Wegen Labels hat das keinen Sinn für Benutzerinteraktion. Wenn Sie Gesten für UILabels hinzufügen möchten, fügen Sie diese einzelne Zeile labelName..isUserInteractionEnabled = true in Swift hinzu. Fügen Sie dann Gesten hinzu.
iOS

Es ist zu spät, Mann, das habe ich schon behoben. Aber danke für den Vorschlag. Ihr Kommentar ist hilfreich für Stapelbenutzer. Geschätzt!
Mihir Oza

1
Ich denke, die Linie setNumberOfTapsRequired:1ist nicht notwendig
Naveed Abbas

9

Nein, Sie sollten Gestenerkenner nicht an mehr als eine Ansicht anhängen.

Diese expliziten Informationen finden Sie in der Apple-Dokumentation:

Gestenerkenner werden an eine Ansicht angehängt

Jeder Gestenerkenner ist einer Ansicht zugeordnet. Im Gegensatz dazu kann eine Ansicht mehrere Gestenerkenner haben, da eine einzelne Ansicht auf viele verschiedene Gesten reagieren kann. Damit ein Gestenerkenner Berührungen erkennt, die in einer bestimmten Ansicht auftreten, müssen Sie den Gestenerkenner an diese Ansicht anhängen.

Handbuch zur Ereignisbehandlung für iOS - Gestenerkenner Apple Developer Library

Während andere erwähnen, dass sie in einigen Fällen möglicherweise funktionieren, ist dies eindeutig gegen die Dokumentation und kann sich in jeder zukünftigen iOS-Version ändern.

Sie können den Ansichten, die Sie überwachen möchten, separate Gestenerkenner hinzufügen, die eine gemeinsame Aktion verwenden können.


4

Nun, wenn jemand nicht codieren möchte, um eine Gestenansicht für mehrere Schaltflächen hinzuzufügen, wie kwalker oben geantwortet hat, und dies über den Interface Builder tun möchte, kann dies hilfreich sein.

1) Sie können Long Press Geste Recognizer aus der Objektbibliothek hinzufügen, wie Sie andere Objekte wie UIButtons und UILabels hinzufügen.

Geben Sie hier die Bildbeschreibung ein Am Anfang habe ich nur einen genommen

2) Setzen Sie Referenzierungssteckdosen auf UIButtonund senden Sie Aktionen mit dem Eigentümer der Datei.

Geben Sie hier die Bildbeschreibung ein

Hinweis: Wenn Sie mehrere UIButton oder ein anderes Objekt haben, benötigen Sie für jedes Objekt eine separate Gestenerkennung. Weitere Einzelheiten entnehmen Sie bitte meiner Frage. Falsches UIButton-Tag bei Gestenerkennung mit langem Druck


Es ist sehr einfach, mit IB mehr als ein UIView an den Guesture Recognition zu binden. Die Frage betraf die Codegenerierung.
AlexeyVMP

3

Wenn Sie eine feste Ansicht haben, empfehle ich Ihnen, so etwas zu tun

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

Auf diese Weise werden mehrere verschiedene nutzlose Variablen reduziert


3

Sie können eine generische Erweiterung in der Ansicht erstellen, um Gestenerkenner einfach hinzuzufügen. Dies ist nur ein Beispiel, aber es könnte so aussehen

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)
    }
  }

}

Um einer Ansicht einen 2-Tap-Erkenner hinzuzufügen, rufen Sie einfach Folgendes auf:

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

Sie können auch einfach einen Wischerkenner hinzufügen

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

und so weiter. Denken Sie daran, dass das Ziel mit dem Selektor verknüpft sein muss.


2

Klasse überschreiben durch ' <UIScrollViewDelegate>'

Und verwenden Sie diese Methode in der Klasse .m:

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

Mit dieser Methode können Sie mehrere Wischvorgänge in einer einzigen Ansicht aktivieren.


2

Wie wäre es, wenn Sie Ihre Geste neu schreiben (neu erstellen)? Jedes Mal, wenn Sie einen Gestenerkenner hinzufügen, der auf dieselbe Funktion verweist. Im folgenden Fall funktioniert es. Ich verwende 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")
}

-6

Sie können dies mit diesem Code tun, meine Ansichten, die Bildansichten in der xib sind.

- (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;
        }
    }
}

1
Sie erstellen mehrere Gestenerkenner. Meine ursprüngliche Frage betraf die Wiederverwendung eines einzelnen Gestenerkenners, was Sie nicht tun können.
Kubi

1
Was bringt es 500, alle Tags Ihrer Ansichten zu ergänzen und dann zu subtrahieren 500? Warum starten Sie Ihre Tags nicht einfach bei 1(oder sogar 0) statt 501?
ma11hew28

@MattDiPasquale, spielt keine Rolle, ob Sie mit dem beginnen möchten. 1Ich habe diesen Code aus meiner App kopiert, von der ich ihn gebe 501. Aber ja, gib nicht 0bcoz, ich habe irgendwo gelesen, dass es immer die Ansicht der Eltern anzeigt, so dass es zu Komplikationen kommt. Glaub mir, ich habe mich dem gestellt.
Dilip

Der Schlüsseltext in der Dokumentation lautet "Die Ansicht stellt einen starken Verweis auf den Gestenerkenner her." Dies bedeutet, dass die Ansicht die Geste besitzt. Die Geste kann nur einen Besitzer haben. Siehe Link
Phantom59
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.