UITapGestureRecognizer - Einzel- und Doppelklick


156

Ich versuche, UITapGestureRecognizerseiner Ansicht 2 hinzuzufügen , eine für Einzel- und eine für Doppel-Tap-Ereignisse. Der Single-Tap-Erkenner funktioniert wie erwartet (alleine). Aber ich scheine nicht in der Lage zu sein, den Doppelklick-Erkenner zum Laufen zu bringen.

Haben Sie versucht , mit Eigenschaften zu experimentieren wie: cancelsTouchesInView, delaysTouchesBeganund delaysTouchesEndeddoch immer noch nicht funktioniert.

Wenn ich zweimal tippe, wird immer die Einzelklopferkennung aktiviert und das Doppelklopfereignis wird auch an die Superansicht gesendet. Der benutzerdefinierte Doppelklick-Erkenner scheint jedoch überhaupt nicht benachrichtigt zu werden.

Dokumentationen scheinen darauf hinzudeuten, dass die 3 oben genannten Eigenschaften für diesen Zweck verwendet werden könnten. Ich bin mir aber nicht sicher, welche Werte eingestellt werden sollen und auf welchen Erkennern (einfach, doppelt oder beides). Hoffe, jemand, der damit vertraut ist, könnte helfen.

Das Folgende ist der letzte aktualisierte Codeblock.

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}

30
Zufälliger Kommentar: Unterstriche in Variablennamen lassen die meisten Objective-C-Programmierer zusammenzucken. Schlimmer ist, dass Ihre Variablennamen nicht beschreibend sind. Warum nicht einfach singleTapRecognizer und doubleTapRecognizer (oder ähnliches) verwenden? Die Eingabe dauert einen Sekundenbruchteil länger, macht Ihren Code jedoch unendlich lesbarer.
UIAdam

Vielen Dank für den Rat, stimmen Sie zu, dass die Variablennamen aussagekräftiger sein sollten. Aber dieses spezielle Codesegment wurde noch nicht fertiggestellt und wird mehr polierten und beschreibenden Code veröffentlichen, wie vorgeschlagen ...
Stanley

Falls jemand anderes ein ähnliches Problem hat. Ich bemühte mich, Doppelklick- und Einzelhahn-Erkenner schnell zusammenarbeiten zu lassen (Einzelhahn funktionierte einwandfrei, aber kein Doppelhahn). Ich habe die Erkenner mit einem Storyboard auf die Szene gezogen. Ich hatte die Handler und die Anweisung: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) in meinem viewDidLoad, aber immer noch kein doppeltes Tippen. Mein fehlendes Puzzleteil bestand darin, das Symbol für die Erkennung von Doppelklicks (aus der oberen Reihe der Szene) über den Teil der Ansicht zu ziehen, in dem die Doppelklicks erkannt werden sollten.
Paulus

1
@UIAdam die Verwendung eines Unterstrichs als Präfix für einen privaten ivar-Namen in objc ist ziemlich häufig, obwohl nein? (kommt aus einem schnellen Hintergrund)
Charlton Provatas

Antworten:


412
UITapGestureRecognizer *singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)] autorelease];
singleTap.numberOfTapsRequired = 1; 
[self.view addGestureRecognizer:singleTap];

UITapGestureRecognizer *doubleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doDoubleTap)] autorelease];
doubleTap.numberOfTapsRequired = 2; 
[self.view addGestureRecognizer:doubleTap];

[singleTap requireGestureRecognizerToFail:doubleTap];

Hinweis: Wenn Sie es verwenden numberOfTouchesRequired , muss es sein .numberOfTouchesRequired = 1;

Für Swift

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)

Vielen Dank für die Antwort. Ich habe Ihren Code ausprobiert, aber er funktioniert immer noch nicht. Es muss noch etwas geben, das ich verpasst hatte. Hast du noch einen Hinweis?
Stanley

Kann ich Ihre Implementierungsdatei dafür haben?
Anil Kothari

@ Stanley: Anils Antwort sollte funktionieren, natürlich müssen Sie auch Handler (doSingleTap, doDoubleTap) bereitstellen
Rok Jarc

Durch einmaliges Tippen wird eine UITableView aktualisiert, die wie erwartet funktioniert. Beim doppelten Tippen wird vorerst nur eine Protokollanweisung mit NSLog ausgegeben. Mein Verdacht ist, dass der Ersthelferstatus nach dem ersten Tippen von der UIView an eine andere Stelle wechselt, da ich nichts explizites an der Antwortkette getan habe.
Stanley

6
Die Lösung funktioniert bei mir. Der Single Tap Selector wird nach einiger Verzögerung ausgelöst.
Vladimir Obrizan

46

Swift 3-Lösung:

let singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

In der Codezeile singleTap.require (toFail: doubleTap) erzwingen wir das Warten auf das einzelne Tippen und stellen sicher, dass das Tap-Ereignis kein doppeltes Tippen ist.


31

Sie müssen die Methode requireGestureRecognizerToFail: verwenden. Etwas wie das:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


Habe gerade versucht, den Methodenaufruf "Fail" mit beiden Erkennern wieder zu verwenden. Funktioniert aber immer noch nicht. Wenn Sie das Double Tap-Ding schon einmal zum Laufen gebracht haben, teilen Sie mir bitte weitere Erfahrungen mit.
Stanley

1
Ich habe genau diesen Code ausprobiert (genau wie Anil es ausführlicher gepostet hat) und er funktioniert für mich.
UIAdam

Danke für den Kommentar, dann muss es noch etwas geben, das ich meinerseits verpasst habe ...
Stanley

Ihr Code ist immer noch mit DelaysTouches und so weiter durcheinander. Stellen Sie sicher, dass es genau dem Code von Anil folgt. Verwenden Sie requireGestureRecognizerToFail nur einmal so, wie wir es haben.
UIAdam

Ich werde heute oder morgen tun, was Sie geraten haben, da mir momentan die Zeit ausgeht. Vielen Dank für Ihre freundliche Unterstützung ...
Stanley

15

// ---- Zuerst müssen Sie die doppelte und einfache Tippgeste zuweisen ------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleSingleTap:)];

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// ----------------------- Anzahl der Abgriffe ---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// ------- Fügen Sie der Ansicht oder Schaltfläche Doppel- und Einzelklick-Geste hinzu -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

Ich bin mir nicht sicher, ob Sie genau danach suchen, aber ich habe Einzel- / Doppelklicks ohne Gestenerkennung ausgeführt. Ich verwende es in einer UITableView, also habe ich diesen Code in der didSelectRowAtIndexPath-Methode verwendet

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

Die Methoden singleTap und doubleTap sind mit NSIndexPath als Parameter nur ungültig:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

Ich hoffe es hilft


Danke für die Antwort, @Novarg. Hatten Sie das Problem mit den DoubleTap-Erkennern?
Stanley

@ Stanley Nein, der SingleTap wartet 0,2 Sekunden vor dem Abfeuern. Und wenn in der Zwischenzeit das zweite Tippen aktiviert wurde, wird die singleTap-Methode abgebrochen.
Novarg

Es sieht sehr vielversprechend aus, danke für Ihre Hilfe. Ich habe heute wieder keine Zeit mehr. Werde es morgen sicher versuchen :)
Stanley

Kreative Antwort;)
Michael

sehr gute Lösung. Ich musste nur tapCount = 0 für jeden Handler (singleTap, doubleTap) hinzufügen, um sicherzustellen, dass auch die folgenden Berührungen erkannt werden.
Sirio

3

Lösung für Swift 2:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)

1

Ich habe UIGestureRecognizerDelegate-Methoden implementiert, um sowohl singleTap als auch doubleTap zu erkennen.

Mach das einfach.

 UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    [doubleTap setDelegate:self];
    doubleTap.numberOfTapsRequired = 2;
    [self.headerView addGestureRecognizer:doubleTap];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap setDelegate:self];
    [doubleTap setDelaysTouchesBegan:YES];
    [singleTap setDelaysTouchesBegan:YES];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

Implementieren Sie dann diese Delegatmethoden.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

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

0

In einigen Ansichten sind eigene Doppelklickerkenner integriert ( MKMapViewals Beispiel). Um dies zu umgehen, müssen Sie die UIGestureRecognizerDelegateMethode implementieren shouldRecognizeSimultaneouslyWithGestureRecognizerund Folgendes zurückgeben YES:

Implementieren Sie zuerst Ihre Doppel- und Einzelerkenner:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

Und dann implementieren:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }

-1

In Bezug auf @ Stanleys Kommentar -

Versuchen Sie nicht, mit Tap-Gesten eine Zeilenauswahl zu erstellen, UITableViewda diese bereits über eine vollständige Tap-Behandlung verfügt.

Sie müssen jedoch "Berührungen in Ansicht abbrechen" auf "Einzelne Tipp-Gestenerkennung" auf "NEIN" setzen, da sonst keine Tippereignisse angezeigt werden.

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.