I have a navigation controller application which has worked perfectly in iOS5/iOS6 overloading the rotation methods in a category as explained in this GIST: https://gist.github.com/lessthanyouthink/3842178 the only difference is that the GIST subclass UINavigationController and I put it in a category. The problem comes when I'm accessing a viewcontroller which supports all orientations put the orientation in landscape and going back to a portrait only viewcontroller. In iOS 6 the preferredInterfaceOrientationForPresentation method is called but not in iOS 7, so it doesnt autorotate to portrait unless I do it (turning the phone).
Any clues about this ??
Related
I have UISplitViewController in StoryBoard that is initial view and I want the app to work only in Landscape mode.
I have restricted orientation to landscape only, and even put in plist Initial interface orientation to Landscape (right home button).
In iOS 6 everything works fine, it shows master and detail view only, but in iOS 5 it is stuck in Portrait mode and only shows Detail view.
Please help me with this, I am stuck with it for last 2 hours...
You need to implement shouldAutorotateToInterfaceOrientation in the view controllers you have contained in the UISplitViewController:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
I am trying to push a portrait only view controller onto a controller that allows portrait or landscape. The issue I'm having is that if the user is in landscape mode and I push the new controller on it will remain in landscape mode and just look all screwed up. How do I force the orientation to change to portrait as the new view controller is pushed on?
KDaker's answer is correct but another option you can think about is whether you can limit navigation when your orientation isn't what you want. This isn't necessarily a good idea but there are situations where it can work well. An example would be if you had a video which when rotated to landscape became full screen and covered your navigation back button until it returns to portrait.
in iOS 5 and anything before you cant 'force' an orientation from one view to another. You can support only one orientation for the project but then allow autorotation. So in your case, you can only allow autorotation and wait for the user to rotate the device.
In iOS 6, they have changed the way orientation handling works, and its become alot more flexible. You now have these methods:
- (NSUInteger)supportedInterfaceOrientations
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
Using these, you can present your view controller in any orientation you prefer, given that it is supported in the former method.
hope this helps.
The app was perfectly fine working in iOS5 in landscape orientation. However in iOS6, it started to use portrait orientation in all view controllers. The methods shouldAutorotateToInterfaceOrientation are not called anymore. I read the new stuff about changed rotation mechanism in iOS6 and I was able to fix that by adding a line in my AppDelegate:
self.window.rootViewController = _viewController
_viewControler is the starting screen (Home-menu). All other view controllers implement shouldAutorotateToInterfaceOrientation method and returns YES for landscape orientations only. So, it's perfectly working solution for the app that needs to support only one orientation.
However, the problem is I need one view controller (lets call it phone-VC) to be presented in portrait orientation. Now, if I want this view controller would be rotated then I need to return YES in Home-menu controller that is assigned to rootViewControler in appDelegate. However, I can't do that because this rootViewController is starting window that need to presented in landscape only, otherwise the layout with graphics in this window will break. But if I don't return YES from its shouldAutorotateToInterfaceOrientation (Home-menu) then the same method is not called in my view phone-VC that needs to be presented in portrait.
Any ideas? Does the assignation of rootViewController is mandatory in AppDelegate?
UPDATE: the problem exists on device (at least on iPhone4).
Yes, from iOS 6.0 onwards, you must have rootviewcontroller assigned to Windows.rootViewController. This controller will decide whether their children rotates or not. By default all orientations supported but you can restrict them by implementing shouldAutoRotate and supportedInterfaceOrientations delegate methods. I had an instance where I didn't have rootviewcontroller assigned to Windows in using MGSplitViewController which was adding viewcontroller as subview to window. I just needed to change it to make rootviewcontroller and all worked fine!
Check UIKit section on Apple documents - iOS 6.0 release notes.
My app runs in portrait mode, but i want to show one screen in landscape mode only as it is a chart. What do i add to my uiviewcontroller to force it into landscape mode only?
I'm sorry but this answer will be very short: If you're using the UINavigationController, you can't. The answer #jer gives is therefore incorrect. The Apple documentation states:
All child view controllers in your UITabBarController or UINavigationController do not agree on a common orientation set.
I recently had this question answered on a bounty and my app rejected in the process. Read up on that here: How to constrain autorotation to a single orientation for some views, while allowing all orientations on others?
The only solution you have, is to throw away the UINavigationController and rewrite it with something of your own.
By presenting and dismissing a view controller modally you can force an orientation. Set animations to "NO" and you can do this without the user even realizing it occurred.
You can read more about this Josh's answer on Is there a documented way to set the iPhone orientation?
I consider it a bit of a hack, but I've successfully implemented code using this premise to force any device orientation.
You implement shouldAutorotateToInterfaceOrientation: and have it return only YES for UIInterfaceOrientationIsLandscape(param) where param is the parameter you declared for the method.
This will support landscape left and landscape right, instead of locking you to only one landscape orientation.
I did some experiments on autorotation.
The situation: I have a TabBar 4(tabs), three should be portrait only. The last one is a UINavigationController, which by itself should not autorotate any of the stacked controllers. It is basically a browsing application, as I show file and folders everything should be portrait. Some times, a special UIViewController is pushed, and I would like only this one to autorotate (it is always the last on the stack). In this last view, the tabbar is hidden.
How I achieved the goal: I subclassed the UITabBarController, to override the standard shouldAutorotate method behaviour:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if([self.selectedViewController isKindOfClass:[UINavigationController class]])
return [[(UINavigationController*)self.selectedViewController visibleViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
else
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
This way, the answer of shouldAutorotate is forwarded to the controlled tabs, and in particular for the UINavigationController, it is again delegated to the visible UIViewController. Basically this works, as I have all the UIViewControllers answering NO, except for the particular one I described above: correctly, when rotating the Simulator, only when the special UIViewController is visible, the interface rotates to landscape, whici is perfect. The Tabbar here is hidden, so user don't get that also that one is rotated (which would be unconsistent in my design: basically whenever the tabbar is visible, which means everywhere except in this special view, the application is portrait only).
The problem is that I would like that, even if the device is still in landscape mode and user pops the special ViewController, the interface should behave consistently and return to portrait mode. Instead, when I pop, the interface stays in landscape (it's not designed in that way so it's a mess, of course) even when showing a UIViewController that would answer NO to shouldAutorotate... this is because (I think) the method is called only when rotation occurs, so until the rotation actually occurs again, the interface is rotated to landscape anyway.
How do avoid this? My first solution would be somehow to intercept the popping of the last view, and rotate manually the view before popping... but I'm not sure, I hope there is some more robust method to handle!!
I use the simulator with 3.0, dunno if this makes a difference.
I know that this is not a solution to your problem, but I think you should really avoid this kind of user interface when portrait-only portrait+landscape or landscape-only pages mixed on the same UINavigationController. Unfortunately the rotation management is extremely buggy and the bugs vary on different firmware versions.
I managed to quite the same thing in one of my projects, but had to remove it later due to firmware bugs: for example if you pressed the "back" button in landscape mode and went back to a portrait-only view, it often occured that the status bar and/or the navigation bar remained in landscape mode and the layout was completely broken. As far as I know this bug is not yet fixed although it was already present in firmware 2.x.
If you still want to do this I suggest the following things:
Make sure that all overridden UIViewController methods (init, viewWillAppear, etc) calls its [super methodName]. If not, auto-rotation is silently buggy. This was mentioned in the "Getting Ready for iPhone OS 3.0 Technical Note" (https://developer.apple.com/iphone/checklist/), but currently this document is unavailable :(
You may experiment with calling the undocumented [UIDevice setOrientation:] method when leaving the landscape view. It sometimes needs to be called twice, once with the current orientation and once with the desired orientation :) You may also need to call [UIDevice setStatusBarOrientation:] if the status bar remains in landscape mode. But note that Apple is likely to reject your application if you use these methods (they introduced an automatic tool some time ago which detects the presence of undocumented symbols in your application).
I had the same problem as you, and I solved this way:
I subclassed the UITabBarController, and added the following code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (self.selectedViewController)
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
else
return (interfaceOrientation == UIDeviceOrientationPortrait);
}
This way, every child view controller could control its own orientation.
The problem is that you are rotating your UITabBarController (with the child view controller on top of it) rather than just the child view controller. You should be able to implement shouldAutorotateToInterfaceOrientation: only in your child view controller and have it work properly. It would also simplify your code.
I have never had this issue, but I've also never implemented shouldAutorotateToInterfaceOrientation: in a "container" view controller like a UITabBarController or UINavigationController.
The problem with your implementation is that you use the visibleViewController member of UINavigationController. You should use topViewController instead and everything will work as expected.