UINavigation with LandscapeRight Only - ios

My Application only supports landscape right.
If I start the app holding iPhone in landscape, all successive views are presented in landscape mode. And they do not autorotate to any orientation since my app forbids that using following code in all view controllers
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
However, if I start the App with iPhone held in Portrait Mode, my views are displayed and pushed in Portrait Mode :o (My view controllers do not support Portait Mode at all)
The very first view of my application is Presented as ModalView on a UINavigationController, which is then dismissed and a new HomeController is pushed on to the stack.
How do I re-structure my Application so that the Navigation Controller Pushes Views Correctly?
Here is some code of my didFinishLaunchingWithOptions method
_splashController = [[SplashController alloc] initWithNibName:kViewForSplash bundle:nil];
_navC = [[UINavigationController alloc] init];
_splashController.navC = _navC;
_navC.navigationBarHidden = YES;
[application setStatusBarHidden:YES];
[self.window addSubview:_navC.view];
[_navC presentModalViewController:_splashController animated:YES];

try setting properties Initial interface orientation and Supported interface orientations
to Landscape (right) in Info.plist
this should force the app to launch in Landscape no matter how you hold it

Related

Launching into portrait-orientation from an iPhone 6 Plus home screen in landscape orientation results in wrong orientation

The actual title for this question is longer than I can possibly fit:
Launching an app whose root view controller only supports portrait-orientation but which otherwise supports landscape orientations on an iPhone 6 Plus while the home screen is in a landscape orientation results in a limbo state where the app's window is in a landscape orientation but the device is in a portrait orientation.
In short, it looks like this:
When it is supposed to look like this:
Steps to Reproduce:
iPhone 6 Plus running iOS 8.0.
An app whose plist supports all-but-portrait-upside-down orientations.
The root view controller of the app is a UITabBarController.
Everything, the tab bar controller and all its descendent child view controllers return UIInterfaceOrientationMaskPortrait from supportedInterfaceOrientations.
Start at iOS home screen.
Rotate to landscape orientation (requires iPhone 6 Plus).
Cold-launch the app.
Result: broken interface orientations.
I can't think of any other way to enforce a portrait orientation except to disable landscape altogether, which I can't do: our web browser modal view controllers need landscape.
I even tried subclassing UITabBarController and overriding supportedInterfaceOrientations to return the portrait-only mask, but this (even with all the other steps above) did not fix the issue.
Here's a link to a sample project showing the bug.
I had the same issue when launching our app in landscape on an iPhone 6 Plus.
Our fix was to remove landscape supported interface orientations from the plist via project settings:
and implement application:supportedInterfaceOrientationsForWindow: in the app delegate:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Apparently the information in your plist is to specify what orientations your app is allowed to launch to.
Setting the statusBarOrientation of the UIApplication seems to work for me. I placed it in the application:didFinishLaunchingWithOptions: method in the app delegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
application.statusBarOrientation = UIInterfaceOrientationPortrait;
// the rest of the method
}
This appears to be a bug in iOS 8 when using a UITabBarController as a root view controller. A workaround is to use a mostly vanilla UIViewController as the root view controller. This vanilla view controller will serve as the parent view controller of your tab bar controller:
///------------------------
/// Portrait-Only Container
///------------------------
#interface PortraitOnlyContainerViewController : UIViewController
#end
#implementation PortraitOnlyContainerViewController
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
#end
// Elsewhere, in app did finish launching ...
PortraitOnlyContainerViewController *container = nil;
container = [[PortraitOnlyContainerViewController alloc]
initWithNibName:nil
bundle:nil];
[container addChildViewController:self.tabBarController];
self.tabBarController.view.frame = container.view.bounds;
[container.view addSubview:self.tabBarController.view];
[self.tabBarController didMoveToParentViewController:container];
[self.window setRootViewController:container];
I only want my app to open in landscape mode (and not exhibit the problem you describe above on the iPhone 6 Plus), so I set Landscape (left home button) and Landscape (right home button) as the only orientations allowed in my app's PLIST file. This fixes the orientation problem when my app opens. However, I need my app to support portrait mode for one view only since I display a UIImagePickerController in my app, which Apple requires to be shown in portrait mode on iPhone.
I was able to support portrait for that one view only, while keeping my app opening in landscape mode, by including the following code in AppDelegate:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskAll;
}
}
I had a very similar problem. I wanted to force portrait mode everywhere except for playing back videos.
What I did was:
1) to force the app orientation to be in portrait in the AppDelegate:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([window.rootViewController.presentedViewController isKindOfClass:[MPMoviePlayerViewController class]])
{
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
2) launching an empty modal view controller fixed the problem in my case.
I launch it in the viewDidLoad of the first view controller that is on the root of my NavigationViewController (the first view controller visible after the application launches):
- (void)showAndHideNamelessViewControllerToFixOrientation {
UIViewController* viewController = [[UIViewController alloc] init];
[self presentViewController:viewController animated:NO completion:nil];
[viewController dismissViewControllerAnimated:NO completion:nil];
}
Please try the following code.
Probably this problem caused by size of keywindow on landscape launch.
// in application:didFinishLaunchingWithOptions: ...
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.window setFrame:[[UIScreen mainScreen] bounds]]; //<- ADD!!
No luck for me the workaround by Jared using a generic container view controller. I've already subclassed tab bar controller with supportedInterfaceOrientations with no luck as well. Regardless of orientation of the 6+ after launch the tab bar's window is reporting frame = (0 0; 736 414)
So far the only workaround I've found is to force the window frame after makeKeyAndVisible
[self.window makeKeyAndVisible];
self.window.frame = CGRectMake(0, 0, MIN(CGRectGetWidth(self.window.frame), CGRectGetHeight(self.window.frame)), MAX(CGRectGetWidth(self.window.frame), CGRectGetHeight(self.window.frame)));
I got same bug on my app, I figured it out with this solution
Firstly it didn't work but after some dig I have to do it on initial controller after splash screen.
Answer is OjbC language let me update it to Swift
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
Don't forget that should on the initial view controller.
For myself, I was having the same issue as jaredsinclair, but subclassing a UIViewController with the supportedInterfaceOrientations method was not solving the issue. Instead I did exactly what he did in my appDidFinishLaunching method of my AppDelegate and added my UITabBarController as a child to a normal UIViewController rather than his subclass and it worked!
I'm in the same situation, and doing [self.window setFrame:...] doesn't work for me.
Adding the following at the end of application:didFinishLaunchingWithOptions is the only thing I've found that works. It makes the screen blink and isn't exactly clean and efficient.
I added this at the end of application:didFinishLaunchingWithOptions:
UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navController presentViewController:nc animated:NO completion:nil];
[self.navController dismissViewControllerAnimated:NO completion:nil];
[UIViewController attemptRotationToDeviceOrientation];
I had a similar issue is with my app runs both in landscape and portrait with a UITabBarController as root view controller.
Whenever the app was launched when in Landscape mode, the view was incorrect.
All I had to do:
- remove rootview controller assignment in the XIB.
- Manually add it in once the app is launched:
(void)applicationDidFinishLaunching:(UIApplication *)application {
application.statusBarHidden = YES;
[self.window setRootViewController:self.tabBarController];
That fixed the problem.
Just Remove All the items in Supported interface orientation except what you want (i need only Portrait) in info.plist , it will work for me
just call
[application setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
in app delegate method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
in fact the device now is UIInterfaceOrientationPortrait after Launching ,if you touch an inputField ,the keyboard is portrait layout

Different supported interface orientations in UINavigationController stack

I have a UINavigationController as my UIWindow's rootViewController and a UIViewController (ControllerA) that supports only Portrait orientation is added to the UINavigationController as its rootViewController.
At some point later, I replace UINavigationController's rootViewController with a new UIViewController (ControllerB). ControllerB supports both Portrait and Landscape. I want my initial screen (ControllerA) to only work in Portrait while the rest of the app can supports both Portrait and Landscape.
[self.navigationController setViewControllers:#[viewControllerB] animated:NO];
| UINavigationController launches:
| ----ControllerA (rootViewController): Portrait only
| ----ControllerB (rootViewController): Portrait and Landscape supported
If I start my app in Landscape which is not handled by ControllerA and then move to ControllerB, my content (+status bar) is still in Portrait. If I manually rotate the device at this point, I have the correct content layout.
How can I make ControllerB render itself in the orientation of the device?
Here's what I'm seeing from both ControllerA and ControllerB viewWillAppear method:
navigationController orientation: UIInterfaceOrientationPortrait
UIViewController interfaceOrientation: UIInterfaceOrientationPortrait
<!-----------!!two values are different!!------------------>
[[UIDevice currentDevice] orientation]: UIDeviceOrientationLandscapeLeft
[[UIApplication sharedApplication] statusBarOrientation]: UIInterfaceOrientationPortrait
Phone is physically held in Landscape at this point in time.
Here is the easiest solution (iOS7 only) but it can be expanded to work down to iOS5.
Just write our own UINavigationController (or write a category) and implement supportedInterfaceOrientations.
#implementation MyNavigationController
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
#end
When you want to know the interface orientation always use UIViewController.interfaceOrientation. The statusbar orientation might be wrong (in case of multiple windows) and the device orientation is totally wrong since the device can be Face Up (laying flat on a table) and you cannot infer the interface orientation from that.

ios 6.0 rotation for only some viewController in a UINavigationController?

I have a UINavigationController with a first ViewController that is a UITabBarController, that should not be rotating...
Then pushed UIViewController should rotate...
So far I have subclassed the UINavigationController and implemented those method :
- (BOOL) shouldAutorotate {
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.visibleViewController supportedInterfaceOrientations];
}
So it is the child controller that choose if it should autorotate...
I have so far managed to block rotation for UITabBarController and allow rotation for the pushed UIViewController.
The Only thing is, if the UIViewController is in landscape mode, and when I pop it, the UITabBarController will be in Landscape mode too, until the phone is put on the portrait mode, it will come back to normal and not rotate anymore...
I would like that when I pop the Landscape UIViewController, that the UITabBarController is already on portrait mode.
This new iOS 6.0 UI rotation management seems to be a pain !
As you rightly say, the device has not been rotated, so the revealed view controller does not insist on rotating the orientation when the old view controller is popped. If that's the behavior you want, use a presented view controller instead.
You can force interface rotation by rotating the status bar, but only if supportedInterfaceOrientations returns 0.

iOS 6 Orientation with NavigationController

I am currently developing an application that works with iOS 5 and iOS 6.
Most of my views are only on Portrait orientation except for 1.
RotationNavigationController : Main UINavigationController that overrides supportedInterfaceOrientation and shouldAutorotate.
PageViewController : Pushed in RotationNavigationController and is displayed in Portrait orientation only.
ImageViewController : Pushed after PageViewController. Is displayed with UIInterfaceOrientationMaskAllButUpsideDown.
Here's what I have in the ImageViewController's ViewDidLoad
- (void)viewDidLoad
{
// currentMask is the value returned by supportedInterfaceOrientation
[(RotationNavigationController*)self.navigationController setCurrentMask:UIInterfaceOrientationMaskAllButUpsideDown];
[(RotationNavigationController*)self.navigationController setShouldAutorotate:YES];
}
And when I popViewController from ImageViewController in landscape, I get back to PageViewController in landscape mode too whereas PageViewController only supports Portrait orientation.
Of course, I reset the mask in the ImageViewController's viewWillDisappear to Portrait.
Is there a way for PageViewController to remain in Portrait orientation ?
Thanks for the link emrys57. I found out the solution down there, and it was quite trivial in the end :
In RotationNavigationController, just add the following method :
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}

iPad Modal View rotates parentViewController View

When the application is in landscape mode (which I plan to force), displaying a modal view causes the parent view to rotate to portrait mode. If I set the return value of shouldAutoRotateToInterfaceOrientation to NO, the parent does not rotate, however the modal then slides in from the side and displays sideways. Below is the code that reveals the modal.
- (IBAction)loadExistingGame:(id)sender {
SavedGamesTableViewController *savedGames = [[SavedGamesTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
savedGames.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:savedGames animated:YES];
[savedGames release];
}
As per request here is the contents of the shouldAutoRotate method of the SavedGamesTableViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
return YES;
}
Ok I figured out what needed to be done to fix it. The plist file that contains a list of the possible orientations needs to be limited to a single landscape view. The parent to the modal table view needs to have the shouldAutoRotateToInterfaceOrientation method return YES only if the orientation matches the only orientation in the plist file.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return interfaceOrientation = UIInterfaceOrientationLandscapeRight;
}
the modal viewcontroller should return NO for the same method.
Based on
When the application is in landscape
mode (which I plan to force),
displaying a modal view causes the
parent view to rotate to portrait
mode.
and
As per request here is the contents of
the shouldAutoRotate method of the
SavedGamesTableViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
return YES;
}
So what you're saying is that the parent view controller is not yet set to force only using landscape orientation, and when you show a modal view that is set to allow all orientations, you're wondering why your parent view rotates to portrait when you rotate the device to portrait? I don't understand your question... aren't you saying that parent view controller is currently set to allow rotation to portrait? Isn't this behaviour exactly what should happen?
I had a similar problem when bringing up a modal mail view. Forcing the rotation didn't work for me, but calling presentModalViewController on the application's main view controller rather than a child view controller solved the issue.
I was seeing the same behavior; in my case the problem was I had implemented shouldAutorotateToInterfaceOrientation to return YES unconditionally for the parent view controller but NOT for the presented modal view controller. So I suspect Shaggy Frog's comment is the key: whether you want to force landscape mode or not, you need to make sure that the two view controllers' shouldAutorotateToInterfaceOrientation implementations agree or weirdness will ensue.
UIViewController *vc = /* create view controller */;
UINavigationController *nc = nil;
if (IOS_VERSION_LESS_THAN_6_0) {
nc = [[MyCustomNavigationControllerSupportingAllOrientations alloc] initWithRootViewController:vc];
} else {
nc = [[UINavigationController alloc] initWithRootViewController:vc];
}
[self.navigationController presentModalViewController:nc animated:YES];
On iOS6 I use a UINavigationController.
On pre-iOS6 I subclass UINavigationController, like this:
#interface MyCustomNavigationControllerSupportingAllOrientations : UINavigationController
#end
#implementation MyCustomNavigationControllerSupportingAllOrientations
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end

Resources