iosiphoneswipeuiswipegesturerecognizer

Setting direction for UISwipeGestureRecognizer


I want to add simple swipe gesture recognition to my view based iPhone project. Gestures in all directions (right, down, left, up) should be recognized.

It is stated in the docs for UISwipeGestureRecognizer:

You may specify multiple directions by specifying multiple UISwipeGestureRecognizerDirection constants using bitwise-OR operands. The default direction is UISwipeGestureRecognizerDirectionRight.

However for me it doesn't work. When all four directions are OR'ed only left and right swipes are recognized.

- (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.");
}

I fixed this with adding four recognizers to the view but I'm curious to know why didn't it work as advertised in docs?

- (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.");
}

Solution

  • Seems like there is a bug. You can specify the allowed direction(s) as you did. But when you try to access the actual direction that triggered the swipe in the action selector method you still get the bit mask you originally set (for the allowed directions).

    This means that checks for the actual direction will always fail when more than 1 direction is allowed. You can see it for yourself quite easily when you output the value of 'direction' in the selector method (ie -(void)scrollViewSwiped:(UISwipeGestureRecognizer *)recognizer).

    Filed a bug report (#8276386) to Apple.

    [Update] I got an answer from Apple saying that the behavior works as was intended.

    So for example in a table view you can swipe left or right in a table view cell to trigger 'delete' (this would have directions of the swipe gesture set to left and right)

    This means that the original workaround is the way it's supposed to be used. The direction property can only be used to get the gestures recognized correctly, but not in the method performed on a successful recognition to compare for the actual direction that triggered the recognition.