I have made a NavigationController structure.
FirstViewController is RootViewController, SecondViewController is a next SubViewController. Each ViewController shouldAutorotateToInterfaceOrientation is a different(refer a following code).
FirstViewController is only portrait available. SecondViewController all support Portrait and landscapeMode.
In FirstViewController after sth button touch, call a pushHandler. next SecondViewController is a pushed.
In SecondViewController after rotated landscape back to the FirstViewController, that orientation is too landscape.
but, I implemented each ViewController orientation different. however each ViewController not independently set orientation. why happen?
How can I viewcontroller each orientation can be set independently, to do?
If SecondViewController change the orientation of the landscapeMode. I want back to the FirstViewController still portraitMode(forever hold portraitState Anything not to be affected).
How do I implements programmatically?
FirstViewController *rootViewController = [FirstViewController alloc] init];
UINavigationController *MyNavigationController = [UINavigationController alloc] initWithRootViewController:rootViewController]];
//FirstViewController
- (void)pushHandler
{
SecondViewController *subViewController = [SecondViewController alloc] init];
[[self navigationController] pushViewController:subViewController animated:YES];
[subViewController release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
//SecondViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Because you use a UINavigationController for all your UIViewControllers whatever orientation behaviour you will set for the UINavigationController will be applied to all it's children or in otherwords objects on its stack.
Think of a UINavigationController as a house and UIViewControllers as rooms. All the rooms in the house will rotate in the same way the house. There is no way to turn a room without turning the house and other rooms.
But as always there are tricks. Look at my answer to this question Only having one view autorotate in xcode?
Related
I am presenting a view controller from another view controller using presentViewController.
The presenting view controller (The "SourceViewController") creates the new view controller and assigns it to a navigation controller before presentation (because the "NextViewController" wants a navigation bar and navigation controller).
// from the source view controller
#implementation SourceViewController
-(void)showNextViewController
{
NextViewController *viewController = [[NextViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self presentViewController:viewController animated:YES];
}
#end
#implementation NextViewController
// in NextViewController
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
But when I present the view controller when the originating view controller is in landscape the "NextViewController" isn't presented in portrait but rather in landscape like the source view controller.
I've tried many combinations of rotation methods but haven't been able to get it to present in the correct orientation.
I assume that it is possible because many apple components like UIImagePickerController are always presented in portrait , so how do I force its orientation?
Thanks
EDIT:
I've created a UINavigationController sub class:
PortraitNavigationController : UINavigationController
#implementation
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end
and then when presenting the NextViewController
PortraitNavigationController *nav = [PortraitNavigationController initWithRootViewController:nextViewController];
[self presentViewController:nav animated:YES];
and now NextViewController is indeed in portrait - but when I rotate the device to use this view controller and eventually dismiss it - the underlying source view controller looks all messed up.
The underlying view controller is a custom container view controller which is embedded in a UINavigationController
The containers it uses to display the child view controllers are not in their correct places
I don't want the container view controller to rotate at all as soon as the NextViewController is displayed and dismissed.
When you rotate your device the presented view controller is asked about the rotations and orientations it supports - In your case it's a UINavigationController and not an instance of NextViewController. One way to fix this is to subclass UINavigationController and override the rotation methods and forward the calls onto it's root view.
As a side not UIImagePickerController is a subclass of UINavigationController. It might make more sense to make NexViewController a subclass of UINavigationController and then inside that subclass initialize it with the correct root view controller.
Another option is to just alloc and init a UINavigationBar inside of NextViewController and add it as a subview if you don't need to use the navigation controller for anything. In this case autolayout comes in handy because you can pin it to the top, left, and right and let it figure out the correct size and location for it.
What is the correct way to propagate shouldAutorotate into a deep modal viewcontroller in iOS6
Consider the following example:
Create a new sample Tabbed Application in XCode 4.5
In the Summary, select all orientations
Create a new simple UITabBarController, e.g. MyTabBarViewController and add the code
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
In the AppDelegate, replace with UITabBarController by MyTabBarViewController in order to hook the rotation
self.tabBarController = [[MyTabBarViewController alloc] init];
Now the rotation should work, and in the FirstViewController, add the code to show a modal viewcontroller on click
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIViewController * viewController2 = [[SecondViewController alloc]
initWithNibName:#"SecondViewController_iPhone" bundle:nil];
[self presentViewController: [[UINavigationController alloc]
initWithRootViewController:viewController2]
animated:YES
completion:nil];
}
Problem:
Now since the SecondViewController is wrapped by a UINavigationController, even I have added shouldAutorotate in SecondViewController and can't make the upside down rotation done right.
The only fix is to create a custom UINavigationController and also implement shouldAutorotate and this should work.
But this approach sound stupid and it require me to fix all UI class by implementing the shouldAutorotate and I cannot use shorthands such as [UINavigationController alloc]
initWithRootViewController... anymore, I must implement all these UITabBarController and UINavigationController.
Are there any better approach?
Have you tried this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
It's a notification sent by the device which tell the observer about the rotation. Do not forget to removeObserver when you don't need anymore
That is not stupid, and it's seems to be the right way.
You could create a subclass of UINavigationController, and use
[[MyNavigationController alloc] initWithRootViewController:...].
In my App I use a UITabbarController, which rotates perfectly to all UIInterfaceOrientations in all viewcontrollers. But when I add an UIView to the UIWindow afterwards it will not be added in the current UIInterfaceOrientation, but always in UInterfaceOrientationPortrait (which is default for the app). It won't rotate to a new orientation also. I add the ViewController by using:
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[self.window addSubview:[loginViewController view]];
I have
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"%#", #"YES IT WILL!");
}
in LoginViewController.m but there will never be logged anything. Any idea why the subview won't rotate?
SideSwipe
EDIT:
Found the solution:
Apparently UIWindow should only have one subview, not more, otherwise things will mess up, so i call:
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[tabBarController presentModalViewController:loginViewController animated:YES];
instead, which will autorotate the loginviewcontrollers view just fine.
I have a view inside another view, when rotation happened, only the parent willRotateToInterfaceOrientation got called, so what I did is add [self.subViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; to parent's willRotateToInterfaceOrientation method.
As you are adding a new subview to window, you have to make the window rotate too.
I have a TabbarController with different ViewControllers.
Some of these ViewControllers should autorotate and one ViewController should be presented only in PORTRAIT.
I fill the Tabbar with the following procedure:
ChartThemeViewController *chartViewController = [[ChartThemeViewController alloc]
initWithTheme:chartThemeDict];
UINavigationController *theNavigationController = [[UINavigationController alloc]
initWithRootViewController:chartViewController];
[chartViewController release];
[localViewControllersArray addObject:theNavigationController];
[theNavigationController release];
tabBarController.viewControllers = localViewControllersArray;
The ChartThemeViewController is a subclass of ThemeViewController.
ThemeViewController is a subclass of UIViewController.
If I override 'shouldAutorotateToInterfaceOrientation' in the subclasses of ThemeViewController, and return YES in all subclasses and return NO in ChartThemeViewController... it happens that all the ViewControllers don't autorotate.
mmmmhhh... hope you can understand this...
How can I solve this problem?
many thanks
jens
I believe the trick to selective autorotation within an instance of UITabBarController is as follows: Subclass UITabBarController and override the method -(BOOL)shouldAutorotateToInterfaceOrientation: with the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [[self selectedViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
};
Now, if you select your portrait-only tab and rotate to landscape, the application will stay in portrait.
A new problem here, though, is as follows: select a tab that does support landscape; rotate to landscape; select a tab that only supports portrait. Uh oh. The portrait-only view controller is being displayed in landscape. Unfortunately, there is no way to force a view controller to a specific orientation.
You can look here for a description of the problem: How to force a screen orientation in specific view controllers?
As you can see, there is no real solution.
I would recommend disabling all tabs that do not support the current orientation. You can override -(void)didAutorotateToInterfaceOrientation: in your UITabBarController subclass with the following to achieve this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation toInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
NSArray *items = [[self tabBar] items];
for (NSUInteger i = 0; i < [items count]; i ++)
{
UITabBarItem *item = [items objectAtIndex:i];
if (![[[self viewControllers] objectAtIndex:i] shouldAutorotateToInterfaceOrientation:toInterfaceOrientation])
{
[item setEnabled:NO];
}
else
{
[item setEnabled:YES];
};
};
};
If you do not wish to do this, then consider altering your interface to be able to support the same orientations in all of your view controllers.
Hope this helps,
Ryan
I am using a ABPersonViewController and ABNewPersonViewController class by pushview controller.
ABPersonViewController *pvc = [[ABPersonViewController alloc] init];
[pvc setPersonViewDelegate:self];
[[self navigationController] pushViewController:pvc animated:YES];
In ABPersonViewController and ABNewPersonViewController page it is displaying in portrait mode. But when I rotate my iPhone then it is perfectly rotating in landscape mode. But I want to stop this rotation. If I rotate my iPhone in landscape mode it's view should be in portrait mode.
The solution for your problem is quite simple: just subclass UINavigationController like this:
#interface UINonRotatingNavigationController : UINavigationController {
}
#end
in your .h file, and in your .m file type:
#implementation UINonRotatingNavigationController {
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Use it as your main navigation controller for the person picker - this should block it from rotating.
Hope this was helpful,
Paul