UITapGestureRecognizer - toque único e toque duplo

156

Estou tentando adicionar 2 UITapGestureRecognizersa uma exibição, uma para toque único e outra para eventos de toque duplo. O reconhecedor de toque único está funcionando conforme o esperado (por conta própria). Mas parece que não consigo fazer o reconhecedor de toque duplo funcionar.

Tentaram experimentar com imóveis como: cancelsTouchesInView, delaysTouchesBegane delaysTouchesEnded, mas ainda não funciona.

Ao tocar duas vezes, o reconhecedor de toque único sempre será ativado e o evento de toque duplo também será enviado para a super visão. Mas o reconhecedor de toque duplo personalizado não parece ser notificado.

As documentações parecem sugerir que as três propriedades mencionadas acima podem ser usadas para esse fim. Mas não tenho certeza de quais valores devem ser definidos e em quais reconhecedores (únicos, duplos ou ambos). Espero que alguém familiarizado com isso possa ajudar.

A seguir, é apresentado o bloco de código atualizado mais recente.

// ****** 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
fonte
30
Comentário aleatório: sublinhados nos nomes das variáveis ​​farão a maioria dos programadores de Objective-C se encolher. O pior é que os nomes das variáveis ​​não são descritivos. Por que não usar apenas singleTapRecognizer e doubleTapRecognizer (ou algo semelhante)? Demora mais uma fração de segundo para digitar, mas torna seu código infinitamente mais legível.
precisa saber é o seguinte
Obrigado pelo conselho, concordo com você que os nomes das variáveis ​​devem ser mais descritivos. Mas este segmento de código em particular não foi finalizado e publicará mais polido e código descritivo como sugerido ...
Stanley
Caso alguém mais tenha um problema semelhante. Lutei para que os reconhecedores de toque duplo e toque único trabalhassem juntos rapidamente (o toque único estava funcionando bem, mas sem toque duplo). Eu arrastei os reconhecedores para a cena usando o storyboard. Eu tinha os manipuladores e a instrução: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) dentro do meu viewDidLoad, mas ainda sem toque duplo. Minha peça que faltava no quebra-cabeça era arrastar o ícone do reconhecedor de toque duplo (da linha superior da cena) sobre a parte da vista em que o toque duplo deveria ser reconhecido.
Paulus
1
@UIAdam usando um sublinhado para prefixar um nome de ivar privado em objc é bastante comum, embora não? (vindo de um fundo swift)
Charlton Provatas

Respostas:

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

Nota: Se você estiver usando, numberOfTouchesRequired ele deve ser .numberOfTouchesRequired = 1;

Para 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
fonte
Obrigado pela resposta, tentei seu código, mas ele ainda não está funcionando. Ainda deve haver algo que eu perdi. Você tem mais alguma dica?
Stanley
posso ter seu arquivo de implementação para isso?
Anil Kothari
@Stanley: Anils resposta deve trabalhar, fora do curso você também tem que fornecer manipuladores (doSingleTap, doDoubleTap)
Rok Jarc
O único toque atualiza um UITableView que está funcionando conforme o esperado. O toque duplo, por enquanto, apenas gera uma instrução de log usando o NSLog. Minha suspeita é que o status de primeiro respondedor vá do UIView para outro lugar após o primeiro toque, pois não fiz nada explicitamente sobre a cadeia de respostas.
Stanley Stanley
6
A solução funciona para mim. O seletor de toque único é acionado após algum atraso.
Vladimir Obrizan
46

Solução 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)

Na linha de código singleTap.require (toFail: doubleTap) , estamos forçando o toque único a aguardar e garantir que o evento tap não seja um toque duplo.

Surya Kameswara Rao Ravi
fonte
31

Você precisa usar o método requireGestureRecognizerToFail:. Algo assim:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

UIAdam
fonte
Tentei usar o método "Fail" para chamar os dois reconhecedores agora novamente. Mas ainda não funciona. Se você já trabalhou com o toque duplo antes, compartilhe um pouco mais da sua experiência comigo.
Stanley
1
Eu tentei esse código exato (o mesmo que o Anil postou com mais detalhes) e funciona para mim.
UIAdam
Obrigado pelo comentário, em seguida, ainda deve haver algo que eu tinha perdido de minha parte ...
Stanley
Seu código ainda mexe com atrasos e toques. Faça com que ele siga exatamente o código de Anil. Use o requireGestureRecognizerToFail apenas uma vez da maneira que temos.
precisa saber é o seguinte
Farei como você recomendou mais tarde hoje ou amanhã, pois estou ficando sem tempo no momento. Graças pela sua ajuda ...
Stanley
15

// ---- primeiro, você precisa alocar o gesto de toque duplo e único ------- //

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

// ----------------------- número de torneira ---------------- //

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

// ------- adicione toque duplo e gesto de toque único na visualização ou botão -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];
Jaspreet Singh
fonte
10

Não tenho certeza se é exatamente isso que você está procurando, mas eu toquei duas vezes sem reconhecer os gestos. Estou usando-o em um UITableView, então usei esse código no método 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;

Os métodos singleTap e doubleTap são anulados com NSIndexPath como parâmetro:

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

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

Espero que ajude

Novarg
fonte
Obrigado pela resposta, @Novarg. Você teve o problema que estou tendo com os reconhecedores do doubleTap?
Stanley Stanley
@ Stanley não, o singleTap aguarda 0,2 segundos antes de disparar. E se nesse meio tempo o segundo toque foi ativado, o método singleTap é cancelado.
Novarg
Parece muito promissor, obrigado por sua ajuda. Hoje estou ficando sem tempo hoje. Vai certamente dar-lhe uma tentativa amanhã :)
Stanley
Resposta criativa;) #
Michael
solução muito boa. Eu só precisava adicionar tapCount = 0 em cada manipulador (singleTap, doubleTap) para garantir que os seguintes toques também sejam reconhecidos.
Sirio
3

Solução para 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)
limfinity
fonte
1

Eu implementei os métodos UIGestureRecognizerDelegate para detectar singleTap e doubleTap.

Apenas faça isso.

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

Em seguida, implemente esses métodos de delegação.

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

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

Algumas visualizações têm seus próprios reconhecedores de toque duplo embutidos ( MKMapViewsendo um exemplo). Para contornar isso, você precisará implementar o UIGestureRecognizerDelegatemétodo shouldRecognizeSimultaneouslyWithGestureRecognizere retornar YES:

Primeiro implemente seus reconhecedores duplos e únicos:

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

E, em seguida, implemente:

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

Em referência ao comentário de @ stanley -

Não tente usar gestos de toque para alinhar as seleções para trabalhar, UITableViewpois ele já possui tratamento de toque completo ....

Mas você deve definir 'Cancela toques na exibição' como 'NÃO' em seus reconhecedores de gestos de toque único ou ele nunca receberá os eventos de toque.

Oliver Dungey
fonte