Gestenerkennungs- und Tastenaktionen

99

Ich habe eine Ansichtshierarchie, die ungefähr so ​​aussieht:

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

Ich habe Gestenerkenner an meine UIView (B) angehängt. Das Problem, mit dem ich konfrontiert bin, ist, dass ich keine Aktionen für den abgerundeten Rechteck-Button bekomme, der sich in der UIView befindet (B). Der SingleTap-Gestenerkenner erfasst / überschreibt das Touch Up Inside-Ereignis der Schaltfläche.

Wie kann ich es zum Laufen bringen? Ich dachte, dass die Hierarchie der Antwortketten sicherstellen wird, dass das Tastenberührungsereignis bevorzugt wird und ausgelöst wird! Was vermisse ich?

Hier ist ein verwandter Code:

#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;
    }
}
Mustafa
quelle
Der einfachste Weg ist, cancelsTouchesInView = false zu setzen
Bagusflyer

Antworten:

176

Bei der Methode "shouldReceiveTouch" sollten Sie eine Bedingung hinzufügen, die NO zurückgibt, wenn sich die Berührung in der Schaltfläche befindet.

Dies ist aus dem Beispiel von 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;
}

hoffe es wird helfen

Bearbeiten

Wie Daniel bemerkte, müssen Sie sich anpassen, UIGestureRecognizerDelegatedamit es funktioniert.

Shani

Shannoga
quelle
1
Ah!!! Ja, ich habe diese -gestureRecognizer: shouldReceiveTouch: -Methode vergessen. Danke, dass du mich in die richtige Richtung gelenkt hast. Dies löst zwar mein Problem, aber ich weiß immer noch nicht, warum die Responderhierarchie in diesem Fall nicht funktioniert. Es sollte wahrscheinlich, aber es wird nicht von Apple gehandhabt.
Mustafa
2
Das Verhalten von UIGestureRecognizer wird eindeutig als von der "normalen" Responderkette getrennt beschrieben. Dies ist eine Designentscheidung von Apple.
Sylvain G.
11
Denken Sie daran, das UIGestureRecognizerDelegate-Protokoll einzuhalten und den Delegaten des UIGestureRecognizer auf dieses Objekt festzulegen.
Daniel
2
Betrachten Sie für eine breitere Verwendung eine Variante der Testklauseln von Ramesh oder Flypig. In meinem Fall habe ich zum Beispiel die folgende Zeile erhalten: if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... Beachten Sie, dass Tabellenansichtszellen in ihrer contentView, die Mitglied einer privaten Klasse ist, "berührt" werden. Daher überprüfen wir dort stattdessen die Klasse der Superview.
Clozach
Danke für die Antwort! In meinem Fall bin ich auf dasselbe Problem gestoßen, habe es aber erst entdeckt, als ich es auf dem tatsächlichen Gerät getestet habe. Das Ausführen der App im Simulator ohne Verwendung von UIGestureDelegate, wie in dieser Antwort angegeben, funktionierte wie erwartet, jedoch falsch.
Luis Artola
51

Ich hatte auch das gleiche Problem, dann habe ich es mit versucht

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

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

Es funktioniert jetzt perfekt .........

Ramesh Chandran A.
quelle
4
Ich habe nur diemyGestureRecognizer.delegate = self;
zero3nna
20

Im Allgemeinen verwenden wir die folgende Delegate-Methode, um die Berührung bei allen Arten von UIControls zu vermeiden:

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

Hinweis: Führen Sie diese Überprüfung NICHT durch (überprüfen Sie den Klassentyp erkenner.ansicht). GestureRecognizerShouldBegin, dies funktioniert nicht.

Fliegenschwein
quelle
11

Hier ist eine Swift 3.0- Version:

extension UIViewController: UIGestureRecognizerDelegate {

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

Vergiss nicht:

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

Marcelo Gracietti
quelle
6

Hier ist eine Swift-Version:

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

Vergiss nicht:

  1. Machen Sie Ihre Klasse konform UIGestureRecognizerDelegate
  2. Machen Sie Ihre tapper Objekt Delegaten selbst (zB: tapper.delegate = self)
rsc
quelle
5

Die beste Lösung ist meiner Meinung nach die Verwendung des folgenden Code-Snippets:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
Langsam
quelle