Riconoscimento dei gesti e azioni dei pulsanti


99

Ho una gerarchia di visualizzazione simile a questa:

UIView (A)
UIView > UIImageView
UIView > UIView (B)
UIView > UIView (B) > Rounded Rect Button
UIView > UIView (B) > UIImageView
UIView > UIView (B) > UILabel

Ho collegato i riconoscitori di gesti alla mia UIView (B). Il problema che sto affrontando è che non ottengo alcuna azione per il pulsante Rounded Rect che si trova all'interno di UIView (B). Il riconoscimento dei gesti singleTap cattura / sovrascrive l'evento Ritocco interno del pulsante.

Come posso farlo funzionare? Ho pensato che la gerarchia della catena del risponditore assicurerà che venga data la preferenza all'evento di tocco del pulsante e verrà attivato! Cosa mi manca?

Ecco un po 'di codice correlato:

#pragma mark -
#pragma mark View lifecycle (Gesture recognizer setup)

- (void)viewDidLoad {
    [super viewDidLoad];

    // double tap gesture recognizer
    UITapGestureRecognizer *dtapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestureRecognizer:)];
    dtapGestureRecognize.delegate = self;
    dtapGestureRecognize.numberOfTapsRequired = 2;
    [self.viewB addGestureRecognizer:dtapGestureRecognize];

    // single tap gesture recognizer
    UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureRecognizer:)];
    tapGestureRecognize.delegate = self;
    tapGestureRecognize.numberOfTapsRequired = 1;
    [tapGestureRecognize requireGestureRecognizerToFail:dtapGestureRecognize];
    [self.viewB addGestureRecognizer:tapGestureRecognize];

    // add gesture recodgnizer to the grid view to start the edit mode
    UILongPressGestureRecognizer *pahGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizerStateChanged:)];
    pahGestureRecognizer.delegate = self;
    pahGestureRecognizer.minimumPressDuration = 0.5;
    [self.viewB addGestureRecognizer:pahGestureRecognizer];

    [dtapGestureRecognize release];
    [tapGestureRecognize release];
    [pahGestureRecognizer release];
}

#pragma mark -
#pragma mark Button actions

- (IBAction)buttonTouchUpInside:(id)sender {
    NSLog(@"%s, %@", __FUNCTION__, sender);
}

#pragma mark -
#pragma mark Gesture recognizer actions


- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)doubleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)longPressGestureRecognizerStateChanged:(UIGestureRecognizer *)gestureRecognizer {

    switch (gestureRecognizer.state) {

        case UIGestureRecognizerStateEnded: {
            NSLog(@"%s", __FUNCTION__);

            break;
        }
        default:
            break;
    }
}

Il modo più semplice è impostare cancelsTouchesInView = false
Bagusflyer

Risposte:


176

Nel metodo "shouldReceiveTouch" dovresti aggiungere una condizione che restituirà NO se il tocco è nel pulsante.

Questo è tratto dall'esempio di Apple SimpleGestureRecognizers .

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

    // Disallow recognition of tap gestures in the segmented control.
    if ((touch.view == yourButton)) {//change it to your condition
        return NO;
    }
    return YES;
}

spero che possa aiutare

modificare

Come ha notato Daniel, devi conformarti UIGestureRecognizerDelegateaffinché funzioni.

shani


1
Ah !!! Sì, ho dimenticato questo metodo -gestureRecognizer: shouldReceiveTouch:. Grazie per avermi indicato la giusta direzione. Anche se questo risolve il mio problema, ma non so ancora perché la gerarchia del risponditore non funziona in questo caso. Probabilmente dovrebbe, ma non è gestito da Apple.
Mustafa

2
Il comportamento di UIGestureRecognizer è chiaramente descritto come separato dalla catena "normale" dei risponditori. Questa è una decisione di progettazione di Apple.
Sylvain G.

11
Ricordarsi di conformarsi al protocollo UIGestureRecognizerDelegate e impostare il delegato di UIGestureRecognizer su quell'oggetto.
Daniel,

2
Per un uso più ampio, prendi in considerazione alcune varianti delle clausole di test di Ramesh o flypig. Nel mio caso, ad esempio, sono finito con la riga: if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... Nota che le celle tableview vengono "toccate" nel loro contentView, che è un membro di una classe privata, quindi controlliamo invece la classe del superview.
clozach

Grazie per la risposta! Nel mio caso, mi sono imbattuto nello stesso problema ma l'ho scoperto solo fino a quando non l'ho testato nel dispositivo reale. L'esecuzione dell'app nel simulatore senza utilizzare UIGestureDelegate come indicato in questa risposta ha funzionato come previsto anche se in modo errato.
Luis Artola

51

Ho anche avuto lo stesso problema, poi ho provato con

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

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

Ora funziona perfettamente .........


4
myGestureRecognizer.delegate = self;
Mi sono

20

In generale, usiamo il metodo delegato di seguito per evitare il tocco in tutti i tipi di controlli UIC:

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

Nota: NON fare questo controllo (controlla il tipo di classe recognition.view) il gestureRecognizerShouldBegin, non funzionerà.


11

Ecco una versione 3.0 di Swift :

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

Non dimenticare di:

Make your tapper object delegate to self (e.g: tapper.delegate = self)


6

Ecco una versione Swift:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

Non dimenticare di:

  1. Rendi la tua classe conforme UIGestureRecognizerDelegate
  2. Fai la tua delegato oggetto tapper di auto (ad esempio: tapper.delegate = self)

5

La soluzione migliore è a mio avviso utilizzare lo snippet di codice di seguito:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
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.