Trying to understand how shouldAutorotateToInterfaceOrientation and UIDeviceOrientationDidChangeNotification

StackOverflow https://stackoverflow.com/questions/9514047

Question

I have an interface that I want to startup in landscape orientation. After startup when the user rotates the device to portrait I am displaying a day view calendar. When returning to landscape orientation the calendar is dismissed. Everything works great in every orientation with my application user interface displaying properly in landscape orientation and the calendar displaying properly in portrait orientation.

The problem is if the user is holding the iPhone in landscape orientation on startup. No matter what I do I cannot get it to startup with my user interface in landscape mode. My UIDeviceOrientationDidChangeNotification method fires twice, the first time [UIDevice currentDevice].orientation is landscape, the second in it is portrait. The end result is the the user interface rotates to portrait mode and displays the day view. Not what I want. I want the user interface to stay in landscape orientation until the user physically rotates the device from landscape to portrait.

I don't understand why it fires with a landscape [UIDevice currentDevice].orientation when the user is holding the device in portrait orientation.

Here is what my code looks like in the viewController...

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {       

    if ((interfaceOrientation == UIDeviceOrientationPortrait)|| (interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)) {            
        return NO;
    } 

    return YES;
}


- (void)viewDidLoad {
    [super viewDidLoad];
        showingCalendar = NO;
        initializing=YES;
        [[UIDevice currentDevice]    beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

}

-(void)didRotate:(NSNotification *)notification {
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;  
    if ((deviceOrientation == UIDeviceOrientationPortrait) || (deviceOrientation == UIDeviceOrientationPortraitUpsideDown))  {            
        if ((!showingCalendar) && (!initializing)) {
            showingCalendar = YES;
            [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];            
            GCCalendarPortraitView *calendar = [[[GCCalendarPortraitView alloc] init] autorelease];
            navigationController = [[UINavigationController alloc] initWithRootViewController:calendar];
            [self presentModalViewController:navigationController animated:YES];
        }
    }else if ((deviceOrientation == UIDeviceOrientationLandscapeRight) || (deviceOrientation == UIDeviceOrientationLandscapeLeft)) {
        if (showingCalendar) {
            showingCalendar = NO;
            if (deviceOrientation == UIDeviceOrientationLandscapeRight){
                [self dismissModalViewControllerAnimated:YES];
            }else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){
                [self dismissModalViewControllerAnimated:YES];
            }
        }else {
            initializing = NO;  
        }            
    }
}
Was it helpful?

Solution

I found a workaround to my problem. In viewDidLoad I started a scheduledTimerWithTimeInterval and moved beginGeneratingDeviceOrientationNotifications to the selector method.

Now the notification never fires more than once. The user gets landscape at startup no matter which way the device is being held and after startup all the rotations work perfectly.

Here is my modified code. Everything else stayed the same...

- (void)viewDidLoad {
    [super viewDidLoad];
    showingCalendar = NO;
    initializing=YES;
    timer =  [NSTimer scheduledTimerWithTimeInterval:.55 target:self selector:@selector(startOrientationNotifications) userInfo:nil repeats: NO];

}


-(void)startOrientationNotifications {
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

}

OTHER TIPS

i wouldn't generate a beginGeneratingDeviceOrientationNotifications,

a simple way could be to use a BOOL to check when portrait is allowed in shouldAutorotateToInterfaceOrientation

something like this:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {       

    if ((interfaceOrientation == UIDeviceOrientationPortrait)|| (interfaceOrientation == UIDeviceOrientationPortraitUpsideDown)) {   

        return portraitIsAllowed;
    } 

    return YES;
}

then just change it when needed in other methods .

And keep in mind that shouldAutorotateToInterfaceOrientation is called every time user rotate device AND also when you load (instantiate) your controller the first time

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top