19

ADDED: You can access this project on github ios6rotations


Sorry guys for asking the question about screen rotation in iOS 6 but this is really a pain in the ass..and I still can't understand it completely - for some reason it behaves differently under certain circumstances.

I have the following simple hierarchy of views in my test app:

What I'm trying to achieve is - to keep blue controller in landscape only and red one is only in portrait.

I have a subclass of UINavigationController with such code inside:

@implementation CustomNavController

- (BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

- (NSUInteger)supportedInterfaceOrientations
{
    return  [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

In my blue controller I implemented this:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscape;
}

And in red controller this:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

Now I have the following behavior:

  1. App started in landscape (OK)
  2. When I press the button my red controller pushed in landscape too (this is not ok because it must be shown in Portrait)
  3. It successfully rotates to portrait but not backward to landscape
  4. If I leave the red controller in Portrait mode my blue controller (which is restricted to landscape) shows in Portrait mode.

P.S. All my rotation methods(posted above) are getting called normally.(by the way why do these methods getting called so many times per screen transition - 5-6 times)

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation does not getting called with pushing

All(except portraitUpsideDown) orientations are included in plist.

The question is - how to force rotation to supported orientation in each controller?

I suggest you to post here (as answers) any 100% working code to handle rotations in ios6 (for example if you have some for iPad with SplitController) - I'll keep this question in favorites to have all in one place when I need to handle some specific situations. Cheers!

ADDED: Please do not post this as answer from landscape to portrait I hope that there' s more elegant way to do it.

Community
  • 1
  • 1
Stas
  • 9,925
  • 9
  • 42
  • 77
  • Why - (BOOL)shouldAutorotate { return YES; } ? – Mihir Mehta Apr 11 '13 at 11:18
  • Because if not the red controller will never rotate to portrait(the same with blue) You can create simple test project and try it out. I've actually tried many-many situations – Stas Apr 11 '13 at 11:20
  • `preferredInterfaceOrientationForPresentation` only gets called when using `presentViewController:animated:`. See my answer below for recommended app behavior from both public API standpoint as well as HIG standpoint. – Léo Natan Apr 15 '13 at 18:55
  • Stas, I still can't push my git change. – Léo Natan Apr 17 '13 at 19:39

6 Answers6

26

Using -[UIDevice setOrientation:] is a private API, and will get your application rejected. See this question.

What you ask is not possible using public API and is also not recommended from HIG standpoint. What is supported and you should implement, is modal presentation of the different view controllers with different supported interface orientation. This is why the default implementation of UINavigationController is to always rotate; it assumes all view controllers have the same supported interface orientations.

Take for example video playback on iPhone. Open the video apps (that comes with iOS). The root view controller only supports portrait orientation. However, start a video, and a modal view controller pops up which only supports landscape interface orientations. This seems exactly the behavior you wish to achieve.

This is why preferredInterfaceOrientationForPresentation is not called. preferredInterfaceOrientationForPresentation only gets called when using presentViewController:animated:.

A small gotcha, if you require a navigation bar in each stage of your scene, you will need to enclose each modal view controller with a navigation controller. You can then pass the required data in prepareForSegue: by accessing topViewController of the navigation controller object in the segue.


Here is an example project which behaves correctly according to your requirements (or at least will give you ideas how to implement):

http://www.mediafire.com/?zw3qesn8w4v66hy

Community
  • 1
  • 1
Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • btw, `preferred` only gets called in blue(landscape) when I returning from red but not in red(which is presented modally in nav)! – Stas Apr 16 '13 at 09:22
  • Great! It would be also great if you use my project and commit changes there – Stas Apr 16 '13 at 16:27
  • I committed a change. I only implemented what was necessary for iOS6. I created an unwind segue for popping the modal back. If you need iOS5, this won't work. But that is beside the point of our exercise. Blue is landscape, red is portrait. – Léo Natan Apr 16 '13 at 16:52
  • Stas, I cannot push my commit for some reason. Have you set it as read-only? – Léo Natan Apr 16 '13 at 17:16
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/28360/discussion-between-stas-and-leo-natan) – Stas Apr 17 '13 at 08:31
  • @LeoNatan http://stackoverflow.com/questions/19651657/rotate-portrait-to-landscape-in-pdfreader-in-ios6-and-ios7 please see this question, and please help me. – SAMIR RATHOD Oct 31 '13 at 05:43
  • @LeoNatan I have another project and same issue here. If you have any solution for this problem then please give me answer – SAMIR RATHOD May 23 '14 at 05:06
  • @SAMIRRATHOD My solution is described in my answer. – Léo Natan May 25 '14 at 19:50
  • 1
    @LeoNatan I am using presentViewController:animated: method but even after that preferredInterfaceOrientationForPresentation does't get called. Any clue? – dev gr Jan 19 '16 at 09:32
  • Like @devgr preferredInterfaceOrientationForPresentation doesn't get called for me either. I'm triggering a segue. Segues are supposed to call `presentViewController()`. The presented view controller is fullscreen which means all the orientation methods should get called. `shouldAutoRotate()` and `supportedInterfaceOrientations()` do get called, just not `preferredInterfaceOrientationForPresentation()`. Man this orientation stuff feels like a mess on iOS, costing me a lot of time. – sleep Apr 14 '16 at 00:16
  • Also tried explicitly presenting by calling `presentViewControllerAnimated()` in code, still `preferredInterfaceOrientationForPresentation()` is not called. – sleep Apr 14 '16 at 00:26
6

My two cents worth.

You can present an empty transparent modal view quickly then dismiss it, maybe on ViewDidLoad: or viewWillAppear: on your ViewController and ViewControllerSecond class as a quick workaround.

Also, in storyboard, you can set ViewController class orientation to landscape visually.

dklt
  • 1,703
  • 1
  • 12
  • 12
3

use this line for programmatically change orientation... work 100%

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

and also when you add this line at that time one warning appear and for remove this warning just add bellow code on you implementation file.. at the top.

@interface UIDevice (MyPrivateNameThatAppleWouldNeverUseGoesHere)
- (void) setOrientation:(UIInterfaceOrientation)orientation;
@end

and after that in bellow method just write this code if required..

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return your supported orientations

 if (currentMainView==blueOne) {
        return toInterfaceOrientation== UIInterfaceOrientationPortrait;
    }
}
Omarj
  • 1,151
  • 2
  • 16
  • 43
  • 1
    Unfortunately this doesn't work for me..red controller still shows in landscape. You can create this project by yourself (it won't take much time) and try it yourself. – Stas Apr 15 '13 at 08:53
  • 1
    I've added this project to github so you don't need to create your own now. – Stas Apr 15 '13 at 09:02
  • Yeah, it works, though animation looks just ugly :( Also it is interesting - could apple reject the project with such code inside? I'd like to use documented methods if possible... – Stas Apr 15 '13 at 11:21
  • I know the animation not good, and no apple will not reject the app because the code. i'm already used the same code in my app and does not reject. :) – Omarj Apr 15 '13 at 12:05
  • First, this is not app-store safe. Second, `setOrientation:` expects a parameter of type `UIDeviceOrientation`, which is not necessarily compatible with `UIInterfaceOrientation`. – Léo Natan Apr 15 '13 at 18:41
  • That's why I still waiting for other answers :) – Stas Apr 16 '13 at 08:50
  • @Stas, I created a test project which behaves exactly how you require. I will update the answer with it attached. – Léo Natan Apr 16 '13 at 16:14
  • This worked wonderfully for me. I wanted to force the view to Landscape programatically. Now I want to see if Apple will reject my code or not. – girish_vr Mar 07 '14 at 17:23
3

I have a similar situation in one of my apps (although do note that I am not using UINavigationController).

Change the shouldAutorotate methods in both of your viewControllers:

//in blue (landscape only)
-(BOOL)shouldAutorotate{
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
        return YES;
    }
    else {
        return NO;
    }
}

//in red (portrait only)
-(BOOL)shouldAutorotate{
    if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
        //note that UIInterfaceOrientationIsPortrait(self.interfaceOrientation) will return yes for UIInterfaceOrientationPortraitUpsideDown
        return YES;
    }
    else {
        return NO;
    }
}

Keep the supportedInterfaceOrientations methods the same.

WolfLink
  • 3,308
  • 2
  • 26
  • 44
  • 1
    Unfortunately this doesn't work..by the by the views behavior is very strange with this implementation. – Stas Apr 17 '13 at 08:29
  • What happens, exactly? It works perfectly for me, but then again, I am not using UINavigationController. – WolfLink Apr 17 '13 at 15:24
  • What is happening is described in the question – Stas Apr 17 '13 at 16:58
  • @WolfLink using xcode 4.5 with ios 6.0 simulator for development i checked my simulator its not working. r u guess i missed any code part... because im new for ios development... – Karthik Apr 30 '13 at 06:12
  • @Karthik you also have to have set all supported interface orientations where you can choose the interface orientations in the project settings. If you need help, detail what exactly is happening I and can do my best to diagnose the problem. – WolfLink May 01 '13 at 01:11
0
#pragma mark- Orientation Delegate Method:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{   Orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (Orientation == UIInterfaceOrientationLandscapeLeft || Orientation == UIInterfaceOrientationLandscapeRight)
    {

        // self.scrollView.contentOffset = CGPointMake(self.view.bounds.size.width,1200);

        [scrollView setScrollEnabled:YES];
        [scrollView setContentSize:CGSizeMake(768, 2150)];


    }else if (Orientation == UIInterfaceOrientationPortrait || Orientation == UIInterfaceOrientationPortraitUpsideDown)
    {

        [scrollView setScrollEnabled:YES];
        [scrollView setContentSize:CGSizeMake(768, 1750)];

    }

}
NorthCat
  • 9,643
  • 16
  • 47
  • 50
  • Welcome to Stack Overflow! Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – Jaime Gómez Mar 05 '15 at 07:16
-2

In order to use navigation with orientation together, you should take a bunch of viewcontrollers like an array.

After that checkout following methods,

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

this changes in your methods will help you a lot.

Enjoy Programming!

Stefan
  • 5,203
  • 8
  • 27
  • 51
Niru Mukund Shah
  • 4,637
  • 2
  • 20
  • 34
  • 1
    I'm not sure that I understand your question..You did the same thing I've done in my Nav - see question.. – Stas Apr 11 '13 at 11:36
  • No @Stas, there's a difference in the content of methods.That's why I've mentioned in my answer "this changes in your methods will help you a lot." – Niru Mukund Shah Apr 11 '13 at 11:37
  • Are you joking or completely do not understand what is going on? Were do you see the difference? My nav has THE SAME methods..Read the question carefully before answering.. – Stas Apr 11 '13 at 11:55
  • Moreover, when you ask any question you should get ready to try the different solutions suggested by your helpers..Otherwise your attitude will not let anybody to answer you ... – Niru Mukund Shah Apr 11 '13 at 12:01
  • Foram the methods you are talking about are implemented in appropriate view controllers. View controller does not have a property `viewControllers` dont you know? Your implementation of these emthods should be in Nav and it is actually there - in my custom nav...happy coding) be more attentive! – Stas Apr 11 '13 at 13:01