Puoi allegare un UIGestureRecognizer a più viste?


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

Nel codice sopra riportato view2vengono riconosciuti solo i tocchi . Se commento la terza riga, i tocchi view1vengono riconosciuti. Se ho ragione e puoi usare il riconoscimento dei gesti solo una volta, non sono sicuro che si tratti di un bug o che abbia bisogno di ulteriore documentazione.

Risposte:


334

A UIGestureRecognizerdeve essere utilizzato con una vista singola. Sono d'accordo che la documentazione è imprevedibile. Che UIGestureRecognizerha una sola viewproprietà lo dà via:

Visualizza

La vista a cui è associato il riconoscimento gesti. (sola lettura)

Vista UIView * di @property (nonatomic, readonly)

Discussione È possibile collegare (o aggiungere) un riconoscimento gesti a un oggetto UIView utilizzando il metodo addGestureRecognizer:.


11
Perché l'aggiunta di un riconoscimento gesti a una vista avviene in fase di esecuzione (rispetto al tempo di compilazione).
TomSwift,

1
Ho capito, ma proprio come rilevare che diciamo che non abbiamo usato una variabile, XCode potrebbe dire in base al codice che abbiamo passato lo stesso riconoscitore a più viste e potrebbe avvisare il programmatore.
Zoltán Matók,

1
L'avvertimento del compilatore relativo a più viste che assegnano lo stesso UITapGestureRecognizer non ha senso, perché potresti volerlo fare apposta, ad esempio se vuoi spostare il riconoscimento dei gesti dei tocchi da una vista all'altra. Detto questo, è una sciocca limitazione che il riconoscimento gesti non può essere utilizzato su più viste.
Erik van der Neut,

1
iOS 9 ora impone una singola visualizzazione per riconoscimento dei gesti, stavo usando il metodo del generatore di interfaccia di seguito, ma ora ricevo il seguente messaggio quando provo ad usarlo (alcuni dettagli tagliati per brevità): AVVERTENZA: Un riconoscimento gesti (< UITapGestureRecognizer: .....>) è stato impostato in uno storyboard / xib per essere aggiunto a più di una vista (-> <UIView:; frame = (0 44; 600 536); autoresize = RM + BM; gestureRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) alla volta, questo non è mai stato permesso ed è ora applicato. A partire da iOS 9.0 verrà messo nella prima vista in cui è caricato.
George Brown,

Se si aggiunge alla vista per la seconda volta, la vista è stata collegata prima che questo riconoscitore si stacchi automaticamente automaticamente. UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];La vista di output1 non ha un array di riconoscitori di gesti; view2 ha un array di riconoscitori di gesti
kokos8998,

48

Ci sono riuscito usando il seguente.

for (UIButton *aButton in myButtons) {

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

}

Quindi nel mio metodo handlePress Longong ho appena impostato un UIButton uguale alla vista del riconoscimento dei gesti e diramare ciò che faccio in base a quel pulsante

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

1
Ottima risposta Grazie mille. Questa potrebbe essere la risposta accettata se la domanda fosse "Come si collega un UIGestureRecognizer a più viste?"
D_D,

7
Questo (o qualcosa di molto vicino a questo) non ha funzionato per me. Ho aggiunto diverse visualizzazioni a un riconoscitore di gesti di tocco in Interface Builder e ho collegato il riconoscitore a un'azione. L'azione veniva chiamata ogni volta che veniva toccata una vista allegata, ma gesture.view era sempre l'ultima vista allegata.
Aneil Mallavarapu

Questa è davvero una bella risposta e anche molto utile e d'accordo con @MicRO +1
Dilip

2
Aneil, è perché non hai creato nuove istanze del riconoscimento gesti. Ciò che sta accadendo nel loop in questa risposta qui è che vengono create nuove istanze di riconoscitori di gesti, ognuna con una sola vista allegata. Tutti possono puntare allo stesso gestore, dove puoi quindi controllare la vista per vedere quale è stato toccato.
Erik van der Neut,

1
Qualcun altro può confermare che questo non funziona più nella versione corrente di Obj-C / Swift?
Maxi Mus,

18

Per Swift 3 nel caso qualcuno lo richieda: Basato sulla risposta Bhavik Rathod sopra.

 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
questo è fondamentalmente la creazione di più gesti per le due viste, sempre la stessa regola: ogni gesto ha solo una vista da
associare

3
No, la funzione crea un gesto ogni volta che viene chiamata
Abdoelrhman,

2
il nome della funzione non è corretto. la funzione logica qui è una funzione ottenente. quindi dovrebbe essere chiamato: getGestureRecognizeperché è quello che fa questa funzione
David cerca

Lavora bene per me! E il codice più pulito rispetto alla creazione di più variabili o l'inserimento di codice intero per la creazione all'interno di addGestureRecognizer
Codenator81

11

Possiamo fare qualcosa del genere, è facile e semplice

1) crea la funzione come sotto nel tuo controller (questa funzione restituirà GestureRecognizer)

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

2) ora imposta questo riconoscimento in più viste

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

Non funziona per me quando uso due etichette anziché le viste.
Mihir Oza,

3
@Mihir Oza, non può funzionare direttamente per UILabels. A causa delle etichette non ha senso per l'interazione dell'utente. Se vuoi aggiungere gesti per UILabels aggiungi questa linea singola labelName..isUserInteractionEnabled = true in Swift. Quindi aggiungi i gesti.
iOS

È troppo tardi amico, l'ho già risolto. Ma grazie per il suggerimento. Il tuo commento sarà utile per gli utenti dello stack. Apprezzato!
Mihir Oza,

1
Immagino che la linea setNumberOfTapsRequired:1non sia necessaria
Naveed Abbas,

9

No, non devi associare i riconoscitori di gesti a più di una vista.

Ci sono queste informazioni esplicite nella documentazione di Apple:

I riconoscitori di gesti sono associati a una vista

Ogni riconoscitore di gesti è associato a una vista. Al contrario, una vista può avere più riconoscimenti di gesti, poiché una singola vista potrebbe rispondere a molti gesti diversi. Affinché un riconoscitore di gesti riconosca i tocchi che si verificano in una particolare vista, è necessario associare il riconoscitore di gesti a quella vista.

Guida alla gestione degli eventi per iOS - Riconoscimento dei gesti Apple Developer Library

Mentre come altri citano potrebbero funzionare in alcuni casi, è chiaramente contro la documentazione e potrebbe cambiare in qualsiasi futura versione di iOS.

Quello che puoi fare è aggiungere riconoscitori di gesti separati alle viste che vuoi monitorare e possono condividere un'azione comune.


4

Bene, se qualcuno non vuole codificare per aggiungere la visualizzazione gestuale per più pulsanti come kwalker ha risposto sopra, e vuole farlo tramite Interface Builder questo può aiutarti.

1) È possibile aggiungere Riconoscimento gesti a pressione lunga dalla Libreria oggetti come se si aggiungessero altri oggetti come UIButtons e UILabels.

inserisci qui la descrizione dell'immagine Inizialmente quello che ho finito per usare è stato quello di prenderne solo uno

2) Impostare i punti di riferimento su UIButtone inviare le azioni con il proprietario del file.

inserisci qui la descrizione dell'immagine

Nota: se si dispone di più UIButton o di qualsiasi altro oggetto, sarà necessario un riconoscimento dei gesti separato per ciascuno di essi. Per maggiori dettagli si prega di fare riferimento a questa mia domanda. Sbagliato tag UIButton su Riconoscimento gesti a pressione lunga


È molto semplice associare più di un UIView al riconoscimento guesture tramite IB. La domanda riguardava la generazione del codice.
AlexeyVMP,

3

se hai una vista fissa ti suggerisco di fare qualcosa del genere

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

in questo modo ridurrà diverse variabili inutili diverse


3

È possibile creare un'estensione generica in vista per aggiungere facilmente i riconoscitori di gesti. Questo è solo un esempio ma potrebbe apparire così

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

}

Per aggiungere un riconoscitore a 2 tocchi su una vista, è sufficiente chiamare:

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

Puoi anche aggiungere facilmente un riconoscitore a scorrimento

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

e così via. Ricorda solo che l'obiettivo deve essere collegato al selettore.


2

Sostituisci classe di ' <UIScrollViewDelegate>'

E usa questo metodo nella classe .m:

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

Questo metodo ti aiuterà ad abilitare lo scorrimento multiplo su una singola vista.


2

Che ne dici di riscrivere (ricreare) il tuo gesto Riconosci ogni volta che aggiungi un riconoscimento gesti che punta alla stessa funzione. Nel caso seguente funziona. Sto usando 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

Puoi farlo usando questo codice my views che sono imageview in 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;
        }
    }
}

1
Stai creando più riconoscitori di gesti; la mia domanda originale era sul riutilizzo di un singolo riconoscimento gestuale, cosa che non puoi fare.
Kubi,

1
Qual è il punto di aggiungere 500a tutti i tag delle visualizzazioni e quindi sottrarre 500? Perché non avviare semplicemente i tag in 1(o anche 0) anziché 501?
ma11hew28,

@MattDiPasquale, Non importa se vuoi iniziare con il 1suo, ho appena copiato questo codice dalla mia app da dove lo sto dando 501. Ma sì, non dare 0bcoz ho letto da qualche parte che indica sempre la visione dei genitori, quindi creerà complicazioni, credimi, l'ho affrontato.
Dilip

Il testo chiave nella documentazione è "La vista stabilisce un forte riferimento al riconoscimento dei gesti". il che significa che la vista possiede il gesto. Il gesto può avere un solo proprietario. Vedi link
Phantom59
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.