Search code examples
ioscocoa-touchcocos2d-iphoneuigesturerecognizeruiswipegesturerecognizer

UISwipeGestureRecognizer doesn't seem to respect current UIDevice orientation on iPhone 3G


I have four UIGestureSwipeRecognizers registered (one for each direction), and they work as intended on an iPhone 4/4S (iOS 4.3 and 5) and iPad 1/2 (iOS 4.NotSure and 5). It is a game, so the only allowed device orientations are LandscapeRight and LandscapeLeft. However, on an iPhone 3G with iOS 4.1, the swipe recognizers respond as if the device were being held in Portrait. In other words, on the iPhone 3G, what should be an Up swipe in LandscapeLeft gets registered as a Right swipe. In fact, all four swipe recognizers behave as if the device were in Portrait; however, I have checked [[UIDevice currentDevice] orientation] and it always returns UIDeviceOrientationLandscapeLeft

Also, the app is a game built upon the cocos2d 1.0.1 template.

What could I be doing wrong?

Here's my code where I register the four swipe recognizers:

_swipeRecognizer_right = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightDetected)];
_swipeRecognizer_right.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:_swipeRecognizer_right];
_swipeRecognizer_right.delegate = self;

_swipeRecognizer_left = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeftDetected)];
_swipeRecognizer_left.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:_swipeRecognizer_left];
_swipeRecognizer_left.delegate = self;

_swipeRecognizer_up = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeUpDetected)];
_swipeRecognizer_up.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:_swipeRecognizer_up];
_swipeRecognizer_up.delegate = self;

_swipeRecognizer_down = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeDownDetected)];
_swipeRecognizer_down.direction = UISwipeGestureRecognizerDirectionDown;
[self.view addGestureRecognizer:_swipeRecognizer_down];
_swipeRecognizer_down.delegate = self;

Solution

  • There's no way around it other than converting the directions. I've done this in Kobold2D's swipe gesture recognizer using this internal method, it should be easy to adapt:

    -(KKSwipeGestureDirection) convertSwipeDirection:(UISwipeGestureRecognizerDirection)uiDirection
    {
        // portrait mode direction remains unchanged
        KKSwipeGestureDirection direction = (KKSwipeGestureDirection)uiDirection;
    
        switch (uiDirection)
        {
            case UISwipeGestureRecognizerDirectionRight:
            {
                switch (director.deviceOrientation)
                {
                    case CCDeviceOrientationPortraitUpsideDown:
                        direction = KKSwipeGestureDirectionLeft;
                        break;
                    case CCDeviceOrientationLandscapeLeft:
                        direction = KKSwipeGestureDirectionUp;
                        break;
                    case CCDeviceOrientationLandscapeRight:
                        direction = KKSwipeGestureDirectionDown;
                        break;
                    default:
                        break;
                }
                break;
            }
    
            case UISwipeGestureRecognizerDirectionLeft:
            {
                switch (director.deviceOrientation)
                {
                    case CCDeviceOrientationPortraitUpsideDown:
                        direction = KKSwipeGestureDirectionRight;
                        break;
                    case CCDeviceOrientationLandscapeLeft:
                        direction = KKSwipeGestureDirectionDown;
                        break;
                    case CCDeviceOrientationLandscapeRight:
                        direction = KKSwipeGestureDirectionUp;
                        break;
                    default:
                        break;
                }
                break;
            }
    
            case UISwipeGestureRecognizerDirectionUp:
            {
                switch (director.deviceOrientation)
                {
                    case CCDeviceOrientationPortraitUpsideDown:
                        direction = KKSwipeGestureDirectionDown;
                        break;
                    case CCDeviceOrientationLandscapeLeft:
                        direction = KKSwipeGestureDirectionLeft;
                        break;
                    case CCDeviceOrientationLandscapeRight:
                        direction = KKSwipeGestureDirectionRight;
                        break;
                    default:
                        break;
                }
                break;
            }
    
            case UISwipeGestureRecognizerDirectionDown:
            {
                switch (director.deviceOrientation)
                {
                    case CCDeviceOrientationPortraitUpsideDown:
                        direction = KKSwipeGestureDirectionUp;
                        break;
                    case CCDeviceOrientationLandscapeLeft:
                        direction = KKSwipeGestureDirectionRight;
                        break;
                    case CCDeviceOrientationLandscapeRight:
                        direction = KKSwipeGestureDirectionLeft;
                        break;
                    default:
                        break;
                }
                break;
            }
        }
    
        return direction;
    }
    

    For those who are using Cocos2D 2.x you should know that CCDirector no longer has the deviceOrientation property. Instead you just get the orientation from UIDevice:

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    

    Then just change all case labels by replacing the CC with the UI prefix, for example

    case CCDeviceOrientationPortraitUpsideDown:
    

    should be changed to:

    case UIDeviceOrientationPortraitUpsideDown: