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
{

}
Stanley
quelle
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)
Anil Kothari
quelle
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.

Surya Kameswara Rao Ravi
quelle
31

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

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

UIAdam
quelle
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];
Jaspreet Singh
quelle
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

Novarg
quelle
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)
Limfinität
quelle
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;
}
iPhoneDeveloper
quelle
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; }
Zerodog
quelle
-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.

Oliver Dungey
quelle