UITapGestureRecognizer - jedno dotknięcie i podwójne dotknięcie

156

Próbuję dodać 2 UITapGestureRecognizersdo widoku, jedno dla zdarzeń z pojedynczym dotknięciem i jedno dla zdarzeń dotknięcia podwójnego. Rozpoznawanie z pojedynczym dotknięciem działa zgodnie z oczekiwaniami (samodzielnie). Ale wydaje mi się, że nie mogę uruchomić rozpoznawania podwójnego dotknięcia.

Próbowali eksperymentować z właściwości, takie jak: cancelsTouchesInView, delaysTouchesBegana delaysTouchesEndedjednak nadal nie działa.

Gdy stuknę dwukrotnie, aparat rozpoznawania pojedynczego dotknięcia będzie zawsze aktywowany, a zdarzenie podwójnego dotknięcia zostanie również wysłane do super widoku. Ale niestandardowy aparat rozpoznawania podwójnego dotknięcia nie wydaje się w ogóle otrzymywać powiadomień.

Dokumentacje wydają się sugerować, że wymienione powyżej 3 właściwości można wykorzystać do tego celu. Ale po prostu nie jestem pewien, jakie wartości należy ustawić i na których aparatach rozpoznających (pojedynczy, podwójny lub oba). Mam nadzieję, że ktoś zaznajomiony z tym może pomóc.

Poniżej znajduje się najnowszy zaktualizowany blok kodu.

// ****** 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
źródło
30
Losowy komentarz: podkreślenia w nazwach zmiennych sprawią, że większość programistów Objective-C wzdrygnie się. Co gorsza, nazwy zmiennych nie są opisowe. Dlaczego nie po prostu użyć singleTapRecognizer i doubleTapRecognizer (lub czegoś podobnego)? Pisanie zajmuje ułamek sekundy dłużej, ale sprawia, że ​​kod jest nieskończenie bardziej czytelny.
UIAdam,
Dzięki za radę, zgadzam się z Tobą, że nazwy zmiennych powinny być bardziej opisowe. Ale ten konkretny segment kodu nie został sfinalizowany i zostanie opublikowany bardziej dopracowany i opisowy kod, zgodnie z sugestią ...
Stanley,
Na wypadek, gdyby ktoś inny miał podobny problem. Starałem się, aby aparaty rozpoznawcze z podwójnym i pojedynczym dotknięciem działały ze sobą w szybkim tempie (pojedyncze dotknięcie działało dobrze, ale bez podwójnego dotknięcia). Przeciągnąłem aparaty rozpoznawcze na scenę za pomocą storyboardu. Miałem programy obsługi i instrukcję: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) w moim viewDidLoad, ale nadal nie ma podwójnego dotknięcia. Moim brakującym elementem układanki było przeciągnięcie ikony rozpoznawania podwójnego dotknięcia (z górnego rzędu sceny) na część widoku, w której miało zostać rozpoznane podwójne dotknięcie.
Paulus
1
@UIAdam używanie podkreślenia do poprzedzania prywatnej nazwy ivar w objc jest dość powszechne, ale nie? (pochodzi z szybkiego tła)
Charlton Provatas

Odpowiedzi:

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

Uwaga: jeśli używasz, numberOfTouchesRequired to musi być .numberOfTouchesRequired = 1;

Dla 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
źródło
Dzięki za odpowiedź, wypróbowałem Twój kod, ale nadal nie działa. Wciąż musi być coś, co przegapiłem. Masz więcej podpowiedzi?
Stanley,
czy mogę prosić o plik implementacyjny do tego?
Anil Kothari,
@Stanley: Odpowiedź Anilsa powinna działać, oczywiście musisz również zapewnić obsługę (doSingleTap, doDoubleTap)
Rok Jarc
Pojedyncze dotknięcie aktualizuje UITableView, który działa zgodnie z oczekiwaniami. Na razie dwukrotne dotknięcie powoduje wyświetlenie instrukcji dziennika za pomocą NSLog. Podejrzewam, że stan pierwszej osoby odpowiadającej przechodzi z UIView do innego miejsca po pierwszym dotknięciu, ponieważ nie zrobiłem nic wyraźnie w sprawie łańcucha odpowiedzi.
Stanley,
6
Rozwiązanie działa dla mnie. Wybierak z pojedynczym zaczepem zostaje wyzwolony z pewnym opóźnieniem.
Vladimir Obrizan
46

Rozwiązanie Swift 3:

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)

W linii kodu singleTap.require (toFail: doubleTap) wymuszamy na pojedynczym dotknięciu czekanie i upewnienie się, że zdarzenie tap nie jest dwukrotnym dotknięciem.

Surya Kameswara Rao Ravi
źródło
31

Musisz użyć metody requireGestureRecognizerToFail:. Coś takiego:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

UIAdam
źródło
Próbowałem teraz ponownie użyć wywołania metody „Niepowodzenie” z obydwoma aparatami rozpoznawczymi. Ale nadal nie działa. Jeśli już wcześniej działało podwójne stuknięcie, podziel się ze mną swoimi doświadczeniami.
Stanley,
1
Wypróbowałem dokładnie ten kod (taki sam jak ten, który opublikował bardziej szczegółowo Anil) i działa dla mnie.
UIAdam
Dziękuję za komentarz, to musi być coś, czego z mojej strony przegapiłem ...
Stanley
Twój kod nadal miesza z opóźnieniami, dotknięciami i tak dalej. Zrób to tak, aby było dokładnie zgodne z kodem Anila. Należy używać requireGestureRecognizerToFail tylko wtedy, gdy mamy to.
UIAdam
Zrobię to, co poradziłeś później, dziś lub jutro, ponieważ na razie kończy mi się czas. Dzięki za życzliwą pomoc ...
Stanley,
15

// ---- najpierw musisz przydzielić gest podwójnego i pojedynczego dotknięcia ------- //

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

// ----------------------- liczba zaczepów ---------------- //

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

// ------- dodaj podwójne dotknięcie i pojedynczy gest dotknięcia widoku lub przycisku -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];
Jaspreet Singh
źródło
10

Nie jestem pewien, czy dokładnie tego szukasz, ale zrobiłem pojedyncze / podwójne dotknięcia bez rozpoznawania gestów. Używam go w UITableView, więc użyłem tego kodu w metodzie didSelectRowAtIndexPath

    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;

Metody singleTap i doubleTap są po prostu void z NSIndexPath jako parametrem:

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

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

Mam nadzieję, że to pomoże

Novarg
źródło
Dzięki za odpowiedź, @Novarg. Czy masz problem, który mam z rozpoznawaniem DoubleTap?
Stanley,
@Stanley nie, singleTap czeka 0,2 sekundy przed wystrzeleniem. A jeśli w międzyczasie aktywowano drugie dotknięcie, metoda singleTap jest anulowana.
Novarg
Wygląda to bardzo obiecująco, dziękuję za pomoc. Dziś znowu kończy mi się czas. Na pewno jutro spróbuję :)
Stanley
Kreatywna odpowiedź;)
Michael
bardzo dobre rozwiązanie. Musiałem tylko dodać tapCount = 0 na każdym module obsługi (singleTap, doubleTap), aby mieć pewność, że kolejne dotknięcia są również rozpoznawane.
Sirio
3

Rozwiązanie dla 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)
jasność
źródło
1

Zaimplementowałem metody UIGestureRecognizerDelegate do wykrywania zarówno singleTap, jak i doubleTap.

Po prostu zrób to.

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

Następnie zaimplementuj te metody delegatów.

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

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}
iPhoneDeveloper
źródło
0

Niektóre widoki mają wbudowane narzędzia rozpoznawania podwójnego dotknięcia ( MKMapViewjako przykład). Aby obejść ten problem, musisz zaimplementować UIGestureRecognizerDelegatemetodę shouldRecognizeSimultaneouslyWithGestureRecognizeri zwrócić YES:

Najpierw zaimplementuj podwójne i pojedyncze urządzenia rozpoznające:

// 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];

A następnie zaimplementuj:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }
zerodog
źródło
-1

W nawiązaniu do komentarza @ stanley -

Nie próbuj używać gestów dotknięcia, aby wybrać wiersz do pracy, UITableViewponieważ ma już pełną obsługę dotknięcia ....

Ale musisz ustawić opcję „Anuluje dotknięcia w widoku” na „NIE” w aparatach rozpoznawania gestów jednym dotknięciem, w przeciwnym razie zdarzenia dotknięcia nigdy nie zostaną wyświetlone.

Oliver Dungey
źródło