I'm having issue with auto rotating in my view which is inside a UINavitionViewController and the navigationViewcontroller is inside a tabBarViewController.
I subclassed tabBarViewController. The problem is the interfaceorientation works fine on the first view inside the tabViewController, but whenever I push to another view it doesn't work.
This is a code in subclass tabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
if([self.selectedViewController isKindOfClass:[UINavigationController class]]){
return [[(UINavigationController*)self.selectedViewController visibleViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
} else {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
}
You should have a UIViewController inside a UINavigationController inside a UITabBarController. The rotation is decided by shouldAutorotateToInterfaceOrientation: in your UIViewController. You need to override that method for every UIViewController to return the desired value, i.e., YES if you want it to rotate and NO if you don't want it to.
You shouldn't override shouldAutorotateToInterfaceOrientation: in UINavigationController or UITabBarController.
You have to override shouldAutorotateToInterfaceOrientation: in the view controllers for all the views in the tab bar.
If a view controller's shouldAutorotateToInterfaceOrientation: returns NO, then the tab bar will not rotate, even if the view is hidden at the time of the rotation.
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.
I have the following view controller set up:
viewController1 is able rotate freely to any orientation except portrait upside down.
viewController2 gets pushed on top of viewController1, and I'd like for it to be the same orientation viewController1 is and I'd like for it not to be able to rotate.
viewController3 gets pushed on top of viewController2. I'd like for viewController3 to be in portrait mode.
I'm having a lot of issues trying to accomplish this in iOS6 (haven't tried yet in iOS5). First off, I have already created my own Navigation Controller and put the following in it:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL) shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
I've tried a lot of different combinations of these things to know avail. Mainly where I'm struggling is forcing vc3 to be presented as portrait if vc2 is in landscape. Any help would be appreciated.
What you're trying to do here is fighting the framework. What you're describing is simply not how a navigation controller architecture works in iOS 6. If you want to show a view controller's view and force rotation, use a presented view controller. That's the only time preferredInterfaceOrientationForPresentation is meaningful, and your view controller's supportedInterfaceOrientations will actually be consulted because, being presented, it will be at the root of the interface.
I have explained in a different answer that it is not supported, in iOS 6, to force rotation when pushing a new view controller on to a navigation controller. You can structure rules about compensatory rotation (i.e. what should happen if the user rotates the device), but you can't force the interface to rotate. The only situation in which iOS 6 is happy to let you force rotation is when presenting or dismissing a view controller (presentViewController:animated: and dismissViewControllerAnimated:).
However, it is possible to use a presented view controller in such a way that it kind of looks like you're pushing onto the navigation controller. I've made a movie showing what I mean:
http://youtu.be/O76d6FhPXlE
Now, that's not totally perfect by any means. There is no rotation animation of the status bar, and there is a kind of black "blink" between the two views - which is intentional, because it's there to cover up what is really going. What's really going on is that there are really two difference navigation controllers and three view controllers, as shown in this screen shot of the storyboard.
What we have is:
a nav controller subclass set to portrait orientation, and its root view controller
a second nav controller subclass set to landscape orientation, and its root view controller, which is black and functions as an intermediary
a third view controller to be pushed onto the second nav controller's stack
When the user asks to go "forward" from the first view controller, we present the second navigation controller, thus seeing the black view controller momentarily, but then we immediately push the third view controller. So we get forced rotation, along with a kind of black flash and a push animation. When the user taps the Back button in the third view controller, we reverse the process.
All the transitional code is in the black view controller (ViewControllerIntermediary). I've tried to tweak it to give the most satisfying animation I can:
#implementation ViewControllerIntermediary {
BOOL _comingBack;
}
- (void) viewDidLoad {
[super viewDidLoad];
self.navigationController.delegate = self;
}
-(void)navigationController:(UINavigationController *)nc
willShowViewController:(UIViewController *)vc
animated:(BOOL)anim {
if (self == vc)
[nc setNavigationBarHidden:YES animated:_comingBack];
else
[nc setNavigationBarHidden:NO animated:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!_comingBack) {
[self performSegueWithIdentifier:#"pushme" sender:self];
_comingBack = YES;
}
else
[self.navigationController dismissViewControllerAnimated:YES
completion:nil];
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;
if (secondController.isPresented)
return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}
And for Swift
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {
if self.window?.rootViewController?.presentedViewController? is SecondViewController {
let secondController = self.window!.rootViewController.presentedViewController as SecondViewController
if secondController.isPresented {
return Int(UIInterfaceOrientationMask.All.toRaw());
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
}
For more details check this link
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];
}
I have made a subclass of TTPhotoViewController, wich when I Rotate iPhone also the current image is rotated but NOT The navigation bar and the toolbar (the bar with prev and next button).
In my subclass I have overide the shouldAutorotateToInterfaceOrientation: method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
I've tried to overide willRotateToInterfaceOrientation:duration: e set up a breakpoint inside but seem that this method is never called.
Make sure all your view controllers i.e. Parent view controllers are allowing rotations.. most likely it is happening because one or more view controller is not returning TRUE for shouldAutorotateToInterfaceOrientation
I solved as follow:
TTPhotoViewController was within a TabBarController and by default TabBarController doesn't return YES for shouldAutorotateToInterfaceOrientation. So just subclass TabBarController and do something like that:
#implementation CustomTabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
#end
I add a small detail: in my firts attempt to rotate the interface i've found that the deviceOrientationDidChange: in TTScrollView.m was commeted out, this is done because if you decomment this code the scroll view have a strange behaviour on landascape rotation.
I have an Universal App that supports all orientations in iPad and only potrait in iPhone / iPod. My code looks somewhat like this:
#implementation UIViewController ( interfaceOrientationHack )
- (void) shouldAutorotateToInterfaceOrientation: ( UIInterfaceOrientation ) toInterfaceOrientation {
if( iPad ) {
return YES;
} else if( toInterfaceOrientation == UIInterfaceOrientationPotrait ) {
return YES;
} else return NO;
}
#end
From one of my controllers, i launch a navigation controller as modal view controller
[ self presentModalViewController: c animated: YES ];
The issue currently is, the modal controller launches correctly in orientation, But when i change my orientation the the modal controller doesn't change its orientation, all the rest of the controllers behave correctly.
Any help will be hugely appreciated. Thanks in advance.
From UIViewcontroller class reference:"By default, the UIViewController class displays views in portrait mode only. To support additional orientations, you must override the shouldAutorotateToInterfaceOrientation: method and return YES for any orientations your subclass supports. If the autoresizing properties of your views are configured correctly, that may be all you have to do."
Since your modal view inherits from UIViewcontroller, you have to override shouldAutorotateToInterfaceOrientation:in your modal view.