UINavigation Controller and Autorotation - iphone

I am using a UINavigationController to push and pop views. The Navigation bar is hidden.
I have RootViewController, which is set to autorotate. It works just fine when it is visible.
I also have GalleryViewController. It has autorotation disabled by just returning no.
My problem is, when GalleryViewController is on the nav stack, RootViewController stops responding to it's autorotate events.
If I am in Portrait, and I rotate the device (while viewing GalleryViewController) and then tap the back button, it pops the GalleryViewController off the stack and reveals the RootViewController, but RootViewController did not change rotation as it should have.
I stuck in the method -viewWillAppear and checked the status of the UIDevice orientation. It gives me the correct orientation for the device.
BTW, I also tried enabling the autorotate in the GalleryViewController. It then rotates the view correctly but still does not rotate the RootViewController.
It seems that when using the navigation controller, only the top of the stack gets rotated.
QUESTION: Since the device knows it's in the correct rotation when -viewWillAppear is called, can I force it to update somehow??
-mark

instead of returning just YES, return (interfaceOrientaion == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeLeft || and so on...) in the RootViewController.
in the GalleryViewController return only one orientation which in our opinion is the default one.
When thus done - everything should work like you want it.

Related

iOS6 Preferred Interface Orientation Not Working

I'm trying to work with the iOS6 Auto-rotation mess.
I've looked at almost every single SO question relating to it, and no matter what I try, I can't get rotation working how I need it.
The app is using storyboards, and the layout is as follows:
Navigation controller ---> Root view controller ---> Tab view controller ---> View controller ---> Landscape view controller.
The view controller auto-rotates when I rotate the simulator, but when segueing back to the previous view (that is set to portrait), the view becomes landscape, when it should be portrait. If I rotate the simulator back, the view auto-rotates to portrait again, but this should've been done automatically!
I've implemented (UIInterfaceOrientation)preferredInterfaceOrientationForPresentationand it doesn't get called in any view controller I put it in.
I've subclassed the NavigationController to return the topViewController's shouldAutoRotate, supportedInterfaceOrientations and preferredInterfaceOrientationForPresentation and auto-rotation when rotating the simulator seems to work, but preferredInterfaceOrientationForPresentation never does its job.
Does anyone have a solution to this?
It would appear Apple have removed the ability to push a view in a specific orientation. preferredInterfaceOrientationForPresentation does get called, but only when popping back or presenting a view controller. I had to present my landscape view rather than push it, and set shouldAutoRotate = NO.
Refer to: In iOS6, trouble forcing ViewController to certain interfaceOrientation when pushed on stack for more details.

Supporting rotation on only a child UIViewController in a hierarchy?

I have a child UIViewController with that's part of a hierarchy with a UITabBarController and a UINavigationBarController. Let's call it ChildViewController; then my hierarchy looks like:
UITabBarController
|
UINavigationViewController [tab 1]
|
SomeParentViewController
|
SomeOtherParentViewController
|
ChildViewController
Now I want only ChildViewController to support rotation to landscape orientation. (It's a view controller that shows a chat view, and the landscape mode is easier for typing for some.) I added method - (BOOL) shouldAutorotateToInterfaceOrientation: to ChildViewController to declare that it supports landscape orientation, but rotating the device had no effect. From debugging, I found that – willAnimateRotationToInterfaceOrientation:duration: wasn't being called.
After some searching around online, I've found that a descendent of a UITabBarController only supports a given orientation if the UITabBarController itself supports that orientation. And, strangely enough, UITabBarController only supports an orientation if the view controllers for each of its tabs support rotation. Like tab 1 above, the view controllers for the other three tabs are UINavigationViewController instances; and, because we must go deeper, each UINavigationViewController only supports orientation if its child view controller supports the orientation.
So at this point, adding adding - (BOOL) shouldAutorotateToInterfaceOrientation: to SomeParentViewController and the children of the other UINavigationController instances allowed ChildViewController to rotate. But now SomeParentViewController and the other three tabs will rotate to landscape, and it looks horrible. I only wanted ChildViewController to support landscape.
As a latch ditch effort, I created my own UITabBarController subclass called RotatingUITabBarController and add a global flag to the ChildViewController class that lets me know if it has been created and is displayed. The RotatingUITabBarController overrides only - (BOOL) shouldAutorotateToInterfaceOrientation: and is implemented as:
if ([ChildViewController isDisplayed]) {
return ((toInterfaceOrientation == UIInterfaceOrientationPortrait) ||
(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
return NO;
Now, if I boot the app, switching to SomeParentViewController or any other tab and rotating the phone does not switch to landscape mode, instead keeping in portrait. So far so good. If I create and display ChildViewController and rotate the phone, it enters landscape. So far so good. But now if I pop ChildViewController to reveal SomeOtherParentViewController, it is also in landscape. And so is SomeParentViewController and every other tab that I switch to.
I'm out of tricks now. Any advice would be much appreciated, thanks!
Perhaps the best model for the kind of behavior you seem to want is the YouTube app. Most the interface is portrait-only, but the view that plays videos works in either portrait or landscape.
If you look at that app, you'll notice that the whole tabbed part of the UI is actually a modal view controller. When you launch the app, the tab bar controller is immediately presented modally. The only time you leave that modal tab bar controller is when you play a video -- you'll notice that the whole tabbed interface slides down to reveal the video view. When the video ends, the tab bar controller is again presented modally.
This is an inversion of the "normal" approach, where you use a modal view controller only briefly, but it works very well in the YouTube app. It may or may not work well for you too. The important thing is to make your app predictable and fluid, and make the user feel in control at all times.

UITabBar and View Controller rotation problems

I have a UITabBar with 2 bar items. The initial orientation of the device is portrait. If I rotate the device to landscape while being at tabBarItem2 the whole thing(Status Bar, TabBar, ViewContent2) rotates fine, but when I press the tabBarItem1 the ViewContent1 is still in Portrait. It also happens if I'm in tabBarItem1, then rotate device to landscape and I go to tabBarItem2.
I'm using the willRotateToInterfaceOrientation method on each view controller to move things.
I think this is happening because it is triggering the actual viewController's willRotateToInterfaceOrientation method and not on both of them.
Any ideas on how to fix that?
Both view controllers need to have
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}

Showing a landscape UIViewController in a portrait UITabBarController/UINavigationController

I understand that this question (or variations of it) has been asked quite a few times, however it's still how to best approach this problem without delving into kludgy hacks.
I have an application with the following layout:
UITabBarController
↳ UINavigationController
↳ PortraitViewController
↳ LandscapeViewController
The first PortraitViewController has its rightBarButtonItem set to a UIBarButtonItem, which calls landscapeButtonPressed:. That method pushes the LandscapeViewController onto the view controller stack.
In LandscapeViewController, I set hidesBottomBarWhenPushed to YES during initialisation, since I only want the navigation bar visible.
I also call setStatusBarOrientation:UIInterfaceOrientationLandscapeRight on [UIApplication sharedApplication] in loadView and viewWillAppear:, and then set it back in to UIInterfaceOrientationPortrait in viewWillDisappear:.
In my shouldAutorotateToInterfaceOrientation: implementation, I return YES only for UIInterfaceOrientationLandscapeRight.
The PortraitViewController looks like this:
Portrait View http://img.skitch.com/20091007-18ur7p3iubkrb1if5cak8wdxkb.png
The LandscapeViewController looks like this:
Broken Landscape View http://img.skitch.com/20091007-f3ki1ga5m4ytkyg3wgwektp86e.png
As you can see, the view is not rotating correctly. If I call the private -[UIDevice setOrientation:] method before I call -[UIApplication setStatusBarOrientation:], I can get the navigation bar to rotate properly, but I'd rather not be calling private methods and there doesn't seem to be a way to get the bounds of my main view for laying out subviews. Using the private method results in this:
Better Landscape View http://img.skitch.com/20091007-8ckbx6gpbiateju9qjgew4x3k2.png
Any ideas on how to solve this problem?
My goal is to have a view in landscape orientation, with valid landscape CGRect coordinates that I can use as the basis for laying out subviews.
Nathan,
I feel that you have set PortraitViewController as the rootViewController of UINavigationController. I also believe that you are restricting the PortraitViewController's orientation only to UIInterfaceOrientationPortrait only in the shouldAutorotateToInterfaceOrientation method. If so then, any view controller that you push will have the orientation of the rootViewController itself unless you are not changing the device orientation by rotating your device.
So if you need the LandscapeViewController in the UIInterfaceOrientationLandscapeRight orientation then just allow this in shouldAutorotateToInterfaceOrientation: method and don't screw things by explicitly setting the device orientation.
The LandscapeViewController is not automatically rotating because interfaceOrientation is UIInterfaceOrientationLandscapeRight, so you have to return YES for UIInterfaceOrientationLandscapeRight
To have your views resizing correctly you have to open your xib file with Interface Builder, then into the Inspector and finally into the tab "Size".

Landscape animation bug when popping view controller in iPhone app

I've recently added landscape autorotation to my iPhone navigation based application, however I'm having a bizarre issue which I have no idea how to fix or whether my code is even the cuplrit. Its bizarre because I'm implementing everything as per the autorotation docs on Apple's developer center (that is responding to shouldAutorotateToBlaBla and making sure my views autoadjust correctly).
The problem is that while pushing view controllers animates correctly, popping them off causing the animation to sometimes shift 20px then animate UP the screen, not from right to left relative to the current rotation.
In other words, when you hit Back in a landscape view controller, instead of animating to the right off the screen, it animates vertically down as if it was in Portrait orientation.
Any clues?
I had this bug, but fixed it by implementing this UIViewController method in every view controller I had.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return interfaceOrientation == UIInterfaceOrientationPortrait | UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}