i'm in really bad situation, i have to submit my app, but i have discovered one problem :
My app is a Nav based app, in this app i want only one controller to be able to landscape :
--> Root Controller --> WelcomeController --> LandscapeController
In the landscape controller i have set two views inside the main view, one is portrait mode to tell the user he has to turn the device, the other is set to landscape (in the main view which is in portrait mode)
I have subclassed my navigation controller : MyNavController in which i have set :
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
So the controller on top of the hierarchy decide if the navController can rotate or no.
in my app delegate i have set :
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (UIInterfaceOrientationMaskAll);
}
so i can have both orientation on my app.
In the Welcome Controller i have set :
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait);
//return (UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return YES;
}
Which means the Welcome Controller can only be in portrait mode.
In the Landscape Controller i have set :
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
- (BOOL)shouldAutorotate
{
return YES;
}
so that the landscape Controller can rotate.
I call Landscape controller using :
LandscapeController *aLandscapeController = [LandscapeController] allo] init....
[self.navigationController pushViewController:aLandscapeController animated:YES];
It works, but sometimes believe me or not, when i push the landscape Controller and that i turn the device, it is the Welcome Controller which become landscape and take only half of the screen because it can't be in landscape and this so bad to me you can't imagine.
What can i do to avoid that ?
i'll take any help, i'll make donation if i have to.
Thank you very much.
Second sentence of the UINavigationController documentation: "This class is not intended for subclassing." Have you tried it without your override to the navigation controller's orientation behavior? Maybe the navigation controller does the right thing by default, which is to query the child controllers to determine what the orientation should be. But by overriding it, you are breaking the correct behavior, which is more complex than you expected during view transitions.
Keep everything the same except use a standard UINavigationController instead of your subclass. Or if your subclass can't be removed for other reasons, for a quick test try commenting out this code:
/*- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}*/
But you can't rely on anything working right if you subclass a class that the documentation says you shouldn't.
Related
I am really trying to understand how the autorotation works in iOS5 and iOS6 with parent and children View Controller.
Let's say I have a RootViewController with three UIViewControllers
The Root View Controller has the three view controllers as Children View Controllers, and is responsible of swapping them UIViewControllers.
Now, I want one of the children view controller to be able to autorotate in all interface orientations, and the other two only Portrait Interface Orientation.
Is this possible? How is it done in iOS 5? And iOS 6?
I am really trying to understand all the shouldAutorotateToInterfaceOrientation: supportedInterfaceOrientations preferredInterfaceOrientationForPresentation shouldAutorotate shouldAutomaticallyForwardRotationMethods methods. But I can't get this to work :\ ........
For those two views (which you want to be available only in portrait mode):
Open their View Controllers, and implement this method:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return UIInterfaceOrientationIsPortrait(toInterfaceOrientation); // don't rotate if it's not portrait.
// if you don't want the upside down portrait mode to be available as well, return the expression from below
// return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
This one is actually deprecated, so you also may want to use this:
- (BOOL) shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
// if you want it to be also in upside down portrait mode, return the expression below
return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown;
}
I have a view controller in my app. Let its first view controller, my first view controller appears in portrait mode in phone, when user rotate phone in landscape mode, first view controller also rotate in landscape mode.
Its working fine, and now I have a button on first view controller, when I touch the button second view controller appears. I just want to do is that the second view controller should always appear in portrait mode, even though the first view controller is in landscape mode.
Is there any methods which I have to override to get this functionality?
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
In second view controller keep this.
In a navigation controller, the orientation of your controller depend on the orientation of the navigation controllerĀ“s root controller.
You have two possibilities:
make your root controller's shouldAutorotateToInterfaceOrientation: return different values depending on which controller is actually shown;
use a transform on you your view controller's view so that it is rotated.
I would give a try to the first way, to start. Have a look at this post for an idea how to do it (just ignore the UITabBarController stuff), or try this (which simply relays the message to the top controller in your navigation hierarchy):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return [self.navigationController.topController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
In order to achieve the same result on iOS6, try and define the following methods:
-(NSUInteger)supportedInterfaceOrientations {
return [self.navigationController.topController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.navigationController.topController preferredInterfaceOrientationForPresentation];
}
What I'm trying to do is the simplest concept. But, I'm just not getting any desired results.
My app is a standard Tab Bar app, all of the view controllers in each of the tabs support Portrait orientation only, which is exactly what I want.
However, in one section of the app, I display a modal view controller, which obviously covers the tab bar controller. It is a text input screen, and I would very much like this view to be able to support Landscape orientation as well as portrait. Then, once the user cancels out of that modal view controller, the tab bar controller would be displayed again, everything in portrait.
I have tried so many things, and nothing works. If I tell the app to support both orientations, then the rotations occur correctly on the modal, but also on the rest of the app, which I do not want.
I have tried implementing all the new shouldAutorotate and supportInterfaceOrientations methods, and nothing ever seems to work.
The closest attempt I had to almost working, was I created a UITabBarController category in my app delegate, to fowarded the shouldAutorotate and supportedInterfaceOrientations. This seemed to work initially, but for some reason, whenever cancelling out of my modal vc, my tab bar portion of the app was always shifted up by 20 pixels up behind the status bar?? I have no idea what that's all about.
I created a test app, in which there is no UITabBarController, and I was able to code my desired behavior with no problem, and it works perfectly. So, clearly something with regard to Tab Bar Controller is making this a difficult issue.
Please let me know what the trick is in solving this simple concept.
Thanks!
I was able to solve this by creating a couple of categories for UITabBarController and UINavigationController. Here is the code I used:
#implementation UITabBarController (rotations)
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
#end
#implementation UINavigationController (navrotations)
- (BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.topViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
#end
Then, of course each view controller I display would simple need to respond to the shouldAutorotate and supportedInterfaceOrientations methods.
Apparently in ios6 and above, the way rotation works is different. So what you have to do is the following
In your .plist support all 4 orientations.
Subclass the UITabBarController (for e.g: CustomTabBarController)
In the CustomTabBarController put the following lines of code
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
In your app delegate or where ever you are initializing UITabBarController, replace those instances with CustomTabBarController instances.
In your modal controller put the lines
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
-(BOOL)shouldAutorotate{
return NO;
}
And it should all work.
Apparently the trick, I found is that, UITabBarController will not listen to your instructions. It will support all the orientations you mention in the .plist.
There fore you have to subclass it.
I tried doing all of the above and it works fine. Do let me know and I can send you the code if you want.
The modal UIViewController's parent auto-rotates, but when the modal VC is up I only want it to appear in portrait and not be rotatable. I have tried simply returning NO from shouldAutorotate... in the modal VC, but no joy. Supporting iOS 5+.
Any help greatly appreciated.
Basically, if you presenting Modal Controller on Any Container Controllers (i.e. UINavigationController) it have autorotation method return YES by default. So you have to make subclass for your UINavigation Controller and Deprecate Autorotation there.
For iOS 5 use method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return (toInterfaceOrientation == UIInterfaceOrientationPortrait) : self.enableRotations;
}
for iOS 6:
- (NSUInteger)supportedInterfaceOrientations {
switch ([UIDevice currentDevice].userInterfaceIdiom) {
case UIUserInterfaceIdiomPad: return UIInterfaceOrientationMaskAll;
case UIUserInterfaceIdiomPhone: return UIInterfaceOrientationMaskPortrait;
}
}
- (BOOL)shouldAutorotate {
return NO;
}
It can be doable, but I would think twice before doing that.
As a user;
I launch the app and use in landscape.
trigger an event (eg. press button).
see a view which is portrait.
rotate the phone and look in portrait.
close the modal view.
get landscape view again.
need to rotate the phone again
Bad usability...
you have to present that new controller on a new navigation controller.This will solve your problem
I want all view controllers to support only portrait mode, except one view controller lets call it "LandscapeSupportViewController" that should support also landscape mode.
The problem is when I'm in LandscapeSupportViewController in landscape mode and then push a new view controller that only support portrait mode, the pushed view controller will be in landscape mode also! How could I force it to be portrait?
I saw few apps that do it, take for example Skype iPhone app, the Messages tab is portrait only -> then if you press to enter the message itself you get a view controller that support landscape also because it make sense to enable landscape mode when user is chatting -> then if you press to view the persons profile, a new view controller will be pushed but in portrait! the same happen if you go back, you will forced to return to portrait even if you came from landscape...
Thanks
I'd had students try to accomplish exactly what you are trying to accomplish, and after much research, the general consensus is: this is a bad idea and requires a lot of (App Store legal) hacks to accomplish, and still doesn't turn out too pretty (status bar, for example, screws up). You'll notice in the Skype app that when you go into the IM section, rotate to landscape, and hit back, the UI "snaps", or sort of gets instantly reloaded.
This is not a good user experience, and I'd recommend rethinking your design to be more in line with what Apple recommends.
If i got you correctly you want to change device orientation in some conditions.
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
set your own orientation using above line, just put this lines inside the if condition. condition is depends on you.
Thank you!!
Write this lines before you push viewController which supported only portrait From landscapeViewController
[appdel.navigationController.view removeFromSuperview];// This navcontroller used with rootviewcontroller
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
[ [UIApplication sharedApplication].self.delegate.window addSubview:appdel.navigationController.view];
self.navigationController.navigationBar.hidden=NO;
Here is a solution.
You can add a category for UINavigationController which manages the view controller orientation. See code below:
#interface UINavigationController (MyViewOrientations)
#end
#implemetation UINavigationController (MyViewOrientations)
- (BOOL)supportLandscapeModeForViewController:(UIViewController *)controller {
return [controller isKindOfClass:[LandscapeSupportViewController class]]
}
- (NSUInteger)supportedInterfaceOrientation {
UIViewController *controller = [self visibleViewController];
NSUInteger orientationMasks = UIInterfaceOrientationMaskPortrait
if([self supportLandscapeModeForViewController:controller]) {
orientationMasks |= UIInterfaceOrientationMaskLandscapeLeft;
orientationMasks |= UIInterfaceOrientationMaskLandscapeRight;
}
return orientationMasks;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
UIViewController *controller = [self visibleViewController];
if([self supportLandscapeModeForViewController:controller]) {
return UIInterfaceOrientationLandscapeLeft; // Your call
}
else {
return UIInterfaceOrientationPortrait;
}
}
- (BOOL)shouldAutorotate {
UIViewController *controller = [self visibleViewController];
return [self supportLandscapeModeForViewController:controller];
}
#end
If the situation is more complex, different views support different orientations. You can override "supportedInterfaceOrientation", "preferredInterfaceOrientationForPresentation", "shouldAutorotate" in your view controllers, and delegate calls from UINavigationController category code with "visibleViewController".