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

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


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 .........


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.


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)


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)

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