Storyboards orientation support for xCode 4.2?
Asked Answered
G

3

13

I upgraded to xCode 4.2 and it's new Storyboards feature. However, could not find a way to support both portrait and landscape.

Of course, I did it programmatically, with 2 views, one for portrait and one for landscape, like in old days, and:

if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) 
    {
        self.view = self.landscapeView;
    }
    else
    {
        self.view = self.portraitView;
    }

But I was looking for a way to do this automatically somehow. I mean, it's xCode 4.2 now, I expected more from it. Thanks all.

==================================
TEMPORARY SOLUTION:

I will present here a temporary solution. I say it's temporary, because I am still waiting for Apple guys to do something really intelligent about this.

I created another .storyboard file, called "MainStoryboard_iPhone_Landscape", and implemented the landscape view controllers there. Actually, it's exactly like normal(portrait) .storyboard, but all screens are in landscape mode.

So I will extract the ViewController from landscape storyboard, and when rotation occurs, just change self.view with the new viewController's view.

1.Generate Notifications when orientation changes:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

2.Look for notifications:

[[NSNotificationCenter defaultCenter] addObserverForName:UIDeviceOrientationDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {    
    // We must add a delay here, otherwise we'll swap in the new view  
    // too quickly and we'll get an animation glitch  
    [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0];
}];

3.Implement updateLandscapeView

- (void)updateLandscapeView {  
 //>     isShowingLandscapeView is declared in AppDelegate, so you won't need to declare it in each ViewController
 UIDeviceOrientation deviceOrientation       = [UIDevice currentDevice].orientation;
 if (UIDeviceOrientationIsLandscape(deviceOrientation) && !appDelegate().isShowingLandscapeView)
 {
     UIStoryboard *storyboard                = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone_Landscape" bundle:[NSBundle mainBundle]];
     MDBLogin *loginVC_landscape             =  [storyboard instantiateViewControllerWithIdentifier:@"MDBLogin"];
     appDelegate().isShowingLandscapeView    = YES;  
     [UIView transitionWithView:loginVC_landscape.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{
         //>     Setup self.view to be the landscape view
         self.view = loginVC_landscape.view;
     } completion:NULL];
 }
 else if (UIDeviceOrientationIsPortrait(deviceOrientation) && appDelegate().isShowingLandscapeView)
 {
     UIStoryboard *storyboard                = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
     MDBLogin *loginVC                       = [storyboard instantiateViewControllerWithIdentifier:@"MDBLogin"];
     appDelegate().isShowingLandscapeView    = NO;
     [UIView transitionWithView:loginVC.view duration:0 options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationCurveEaseIn animations:^{
         //>     Setup self.view to be now the previous portrait view
         self.view = loginVC.view;
     } completion:NULL];
 }}

Good luck to everybody.

P.S: I will accept Ad Taylor's answer, because, after much time waiting and searching for a solution, I finished up implementing something inspired from his answer. Thanks Taylor.

Griffith answered 18/10, 2011 at 6:59 Comment(1)
self.view = newView; will the crash the app on iOS 6+Foreandafter
J
6

This is an old question but I read this earlier in the day and then had to spend a fair amount of time work out a better solution. I came up with this solution from hacking up the Apple Alternate View example. Basically it is serving up a modal view for the landscape view.

#pragma mark Rotation view control

- (void)orientationChanged:(NSNotification *)notification
{
    // We must add a delay here, otherwise we'll swap in the new view
    // too quickly and we'll get an animation glitch
    [self performSelector:@selector(updateLandscapeView) withObject:nil afterDelay:0];
}

- (void)updateLandscapeView
{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    if (UIDeviceOrientationIsLandscape(deviceOrientation) && !self.isShowingLandscapeView)
    {
        [self performSegueWithIdentifier: @"toLandscape" sender: self];
        self.isShowingLandscapeView = YES;
    }
    else if (deviceOrientation == UIDeviceOrientationPortrait && self.isShowingLandscapeView)
    {
        [self dismissModalViewControllerAnimated:YES];
        self.isShowingLandscapeView = NO;
    }    
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Jaworski answered 27/1, 2012 at 18:4 Comment(1)
I accepted your answer, because this inspired me to solve my problem. However, instead of present/dismiss modalViewController, I am just transitioning to another view. Thanks Taylor.Griffith
B
3

You shouldn't generally be thinking of separate views for different orientations unless they are widely different (which, arguably, they shouldn't be). Instead, you should rely on autoresizing masks to lay out as much of your view's content based on basic restraints when the superview's frame changes. This will allow subviews to respond appropriately to a change in their superview's frame, often as a result of an interface orientation change.

To answer your question more directly, no, there is no way for Xcode to assume or be told which views you want to use for a particular interface orientation as this was never the intent of UIKit's view architecture.

Here is more information about autoresizing masks: Handling Layout Changes Automatically Using Autoresizing Rules.

Blockade answered 18/10, 2011 at 7:4 Comment(2)
Thanks for answer. But until 4.2, we had the option to add 2 views to one ViewController, and configure them separately, portrait and landscape. I see now we CAN add a second view in a ViewController, but we cannot see it. Click on it to configure, and you cannot see it. And there are some cases (I have many of them) when Autoresizing is really not helpful. What are we supposed to do then?Griffith
Ah, I see what you mean now. This seems to be a bug with Storyboards (or perhaps the desired behavior). I've noticed the same thing, and it can be a pain. I suggest filing a bug with Apple.Blockade
L
3

In XCode v4.2.1 when using StoryBoards you can only change the orientation of the View Controller, and not the View itself, so if you have inserted another view there you wouldn't be able to change it's orientation, even if you could see the View properly.

So the previous way of having two Views would not appear to work when using StoryBoards (when using NIB's where the View Orientation is changeable for separate Views).

Limekiln answered 12/1, 2012 at 14:45 Comment(1)
Hmm, and how would you deal with this issue, when you need portrait and landscape, but when Autorotation is not enough? I still don't have an option. I want for Main Menu view controller, as e.g., to have menu arranged different in landscape mode than how it is in portrait mode. Any idea please?Griffith

© 2022 - 2024 — McMap. All rights reserved.