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
{

}

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)

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.


31

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

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


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

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


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)

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

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

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.