Definindo a direção para UISwipeGestureRecognizer

132

Desejo adicionar um simples reconhecimento de gesto de furto ao meu projeto de iPhone baseado em exibição. Gestos em todas as direções (direita, baixo, esquerda, cima) devem ser reconhecidos.

É indicado nos documentos para UISwipeGestureRecognizer:

Você pode especificar várias direções especificando várias constantes UISwipeGestureRecognizerDirection usando operandos OR bit a bit. A direção padrão é UISwipeGestureRecognizerDirectionRight.

No entanto, para mim, isso não funciona. Quando todas as quatro direções são OR'ed, apenas desliza para a esquerda e para a direita.

- (void)viewDidLoad {
    UISwipeGestureRecognizer *recognizer;

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionUp)];
    [[self view] addGestureRecognizer:recognizer];
    [recognizer release]; 
    [super viewDidLoad];
}

-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
    NSLog(@"Swipe received.");
}

Corrigi isso adicionando quatro reconhecedores à exibição, mas estou curioso para saber por que não funcionou como anunciado nos documentos?

- (void)viewDidLoad {
    UISwipeGestureRecognizer *recognizer;

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
    [[self view] addGestureRecognizer:recognizer];
    [recognizer release];

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionUp)];
    [[self view] addGestureRecognizer:recognizer];
    [recognizer release];

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionDown)];
    [[self view] addGestureRecognizer:recognizer];
    [recognizer release];

    recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    [recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
    [[self view] addGestureRecognizer:recognizer];
    [recognizer release];

    [super viewDidLoad];
}

-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
    NSLog(@"Swipe received.");
}
sandisn
fonte
3
é totalmente independente, mas [super viewDidLoad]; deve ser a primeira declaração em - (void) viewDidLoad
Mihir Mehta

Respostas:

115

Parece que há um erro. Você pode especificar as direções permitidas como você fez. Porém, ao tentar acessar a direção real que acionou o furto no método seletor de ações, você ainda obtém a máscara de bit que definiu originalmente (para as direções permitidas).

Isso significa que as verificações da direção real sempre falham quando mais de 1 direção é permitida. Você pode vê-lo com bastante facilidade quando gera o valor de 'direction' no método seletor (ou seja -(void)scrollViewSwiped:(UISwipeGestureRecognizer *)recognizer).

Arquivou um relatório de bug (# 8276386) na Apple.

[Atualização] Eu recebi uma resposta da Apple dizendo que o comportamento funciona conforme o planejado.

Assim, por exemplo, em uma exibição de tabela, você pode deslizar para a esquerda ou direita em uma célula da exibição de tabela para acionar 'excluir' (isso teria as direções do gesto de deslizamento definidas para esquerda e direita)

Isso significa que a solução original é a maneira como deve ser usada. A propriedade direction pode ser usada apenas para obter os gestos reconhecidos corretamente, mas não no método executado em um reconhecimento bem-sucedido para comparar com a direção real que acionou o reconhecimento.

RupertP
fonte
35
Estou disposto a apostar que quase todo mundo que primeiro usa o reconhecedor de gestos de furto faz exatamente a mesma suposição incorreta sobre como a propriedade direction deve funcionar.
memmons
É bobagem ter que criar 4 reconhecedores diferentes para rastrear deslizes para cima, para baixo, esquerda e direita, mas aí está.
memmons
wow que tipo de porcaria, não um grande negócio, mas parece ser algo que poderia ter acrescentado
marchinram
2
O arquivo de cabeçalho diz: @property (nonatomic) UISwipeGestureRecognizerDirection direction; // o padrão é UISwipeGestureRecognizerDirectionRight. a direção desejada do furto. múltiplas direcções pode ser especificada
nicktmro
1
Concordou que isso parece uma implementação estranha da parte da Apple. Você deve poder especificar várias direções e testar uma dessas direções.
7277 ChrisP
25

Percebi que os gestos esquerdo / direito e para cima / para baixo funcionam juntos em pares, então você só precisa especificar dois reconhecedores de gestos. E os documentos parecem estar errados.

Lars
fonte
Esta é a solução correta. 2 GRs, um para cima e para baixo / um para esquerda e direita. Bingo!
logancautrell
22

Bem, isso é péssimo, resolvi o problema adicionando 2 gestos como o Lars mencionado e que funcionaram perfeitamente ...

1) Esquerda / Direita 2) Cima / Baixo

  

UISwipeGestureRecognizer *swipeLeftRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    [swipeLeftRight setDirection:(UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft )];
    [self.view addGestureRecognizer:swipeLeftRight];

    UISwipeGestureRecognizer *swipeUpDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    [swipeUpDown setDirection:(UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown )];
    [self.view addGestureRecognizer:swipeUpDown];
yunas
fonte
13
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(didSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];

recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(didSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];

Agora esta é a função didSwipe

- (void) didSwipe:(UISwipeGestureRecognizer *)recognizer{
      if([recognizer direction] == UISwipeGestureRecognizerDirectionLeft){
          //Swipe from right to left
          //Do your functions here
      }else{
          //Swipe from left to right
          //Do your functions here
      }
 }
KarenAnne
fonte
5

Se você estiver usando o Xcode 4.2, poderá adicionar Gesture Recognizers @ no storyboard e vincular os GUI Gesture Recognizers às IBActions.

Você pode encontrar os reconhecedores de gestos na biblioteca de objetos do painel Utilitário (parte inferior do painel Direito).

Então é apenas uma questão de arrastar o controle para a ação apropriada.

Grymm
fonte
5

Se você quiser detectar todas as quatro direções, precisará criar quatro instâncias, como fez em sua solução alternativa.

Eis o porquê : A mesma instância do UISwipeGestureRecognizer que você cria é a instância que é passada ao seletor como remetente. Portanto, se você configurá-lo para reconhecer todas as quatro direções, ele retornará verdadeiro para sgr.direction == xxxonde xxx é qualquer uma das quatro direções.

Aqui está uma solução alternativa que envolve menos código (assume o uso do ARC):

for(int d = UISwipeGestureRecognizerDirectionRight; d <= UISwipeGestureRecognizerDirectionDown; d = d*2) {
    UISwipeGestureRecognizer *sgr = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFrom:)];
    sgr.direction = d;
    [self.view addGestureRecognizer:sgr];
}
tybro0103
fonte
2

Aqui está um exemplo de código para o uso do UISwipeGestureRecognizer. Anote comentários.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //add gesture recognizer. The 'direction' property of UISwipeGestureRecognizer only sets the allowable directions. It does not return to the user the direction that was actaully swiped. Must set up separate gesture recognizers to handle the specific directions for which I want an outcome.
    UISwipeGestureRecognizer *gestureRight;
    UISwipeGestureRecognizer *gestureLeft;
    gestureRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRight:)];//direction is set by default.
    gestureLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeft:)];//need to set direction.
    [gestureLeft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
    //[gesture setNumberOfTouchesRequired:1];//default is 1
    [[self view] addGestureRecognizer:gestureRight];//this gets things rolling.
    [[self view] addGestureRecognizer:gestureLeft];//this gets things rolling.
}

swipeRight e swipeLeft são métodos usados ​​para executar atividades específicas com base na passagem para a esquerda ou direita. Por exemplo:

- (void)swipeRight:(UISwipeGestureRecognizer *)gesture
{
    NSLog(@"Right Swipe received.");//Lets you know this method was called by gesture recognizer.
    NSLog(@"Direction is: %i", gesture.direction);//Lets you know the numeric value of the gesture direction for confirmation (1=right).
    //only interested in gesture if gesture state == changed or ended (From Paul Hegarty @ standford U
    if ((gesture.state == UIGestureRecognizerStateChanged) ||
    (gesture.state == UIGestureRecognizerStateEnded)) {

    //do something for a right swipe gesture.
    }
}
Greg
fonte
2
UISwipeGestureRecognizer *Updown=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleGestureNext:)];
            Updown.delegate=self;
            [Updown setDirection:UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp];
            [overLayView addGestureRecognizer:Updown];

            UISwipeGestureRecognizer *LeftRight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleGestureNext:)];
            LeftRight.delegate=self;
            [LeftRight setDirection:UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight];
            [overLayView addGestureRecognizer:LeftRight];
            overLayView.userInteractionEnabled=NO;


    -(void)handleGestureNext:(UISwipeGestureRecognizer *)recognizer
    {
        NSLog(@"Swipe Recevied");
        //Left
        //Right
        //Top
        //Bottom
    }
bhavik
fonte
2

Swift 2.1

Eu tive que usar o seguinte

    for var x in [
        UISwipeGestureRecognizerDirection.Left,
        UISwipeGestureRecognizerDirection.Right,
        UISwipeGestureRecognizerDirection.Up,
        UISwipeGestureRecognizerDirection.Down
    ] {
        let r = UISwipeGestureRecognizer(target: self, action: "swipe:")
        r.direction = x
        self.view.addGestureRecognizer(r)
    }
Andrei
fonte
1

hmm, estranho, funciona perfeito para mim, faço exatamente a mesma coisa

acho que você deveria tentar olhar

Método UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UISwipeGestureRecognizer *)gestureRecognizer {
   // also try to look what's wrong with gesture
   NSLog(@"should began gesture %@", gestureRecognizer);
   return YES;
}

nos logs, você deve ver algo como:

deveria começar gesto; target = <(action = actionForUpDownSwipeGestureRecognizer :, target =)>; direction = cima, baixo, esquerda, direita>

iFreeman
fonte
O que não funciona? gestoRecognizerShouldBegin: funciona bem.
Danyal Aytekin
1

use isso, deve ser a operação bit

   gesture.direction & UISwipeGestureRecognizerDirectionUp || 
   gesture.direction & UISwipeGestureRecognizerDirectionDown
William Wu
fonte
0

Isso estava me deixando louco. Finalmente, descobri uma maneira confiável de ter vários swipeGestureRecognizers.

Parece que há um erro no iOS se o nome do seu seletor de "ação" for o mesmo em vários swipeGestureRecognizers. Se você apenas os nomear de maneira diferente, por exemplo, handleLeftSwipeFrom e handleRightSwipeFrom, tudo funcionará.

UISwipeGestureRecognizer *recognizer;

recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleLeftSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];

recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipeFrom:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
Alex
fonte