I have one application in which a tab bar controller is having 3 tabs and each tab having a view controller.
View controller 1 and 2 are supporting only portrait mode but view controller in tab 3 supports all orientations -portrait, landscape left, landscape right and portrait upside down.
For tab 3, We have to show a particular view when device is in portrait mode and another view when device is in landscape mode.
If device is in portrait mode and user clicks on the tab 3, view is loaded correctly in portrait mode and then if we rotate the device to landscape mode the landscape view is loaded correctly.
But it we turn the device to landscape mode in the tab 1 itself and then click on the tab 3 , then the problem occurs then it shows the screen to be shown in landscape mode but it displays it as a portrait view.
When I tried to find out the reason for this in the delegate method by NSLogging
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
the value of the interfaceOrientation is 1 which is UIInterfaceOrientationPortrait
and the control is going into the if condition written for the portrait mode
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
and when I tried to print the value of UIDevice orientation in the same delegate method
UIDeviceOrientation interfaceOrientation = [UIDevice currentDevice].orientation;
NSLog(#" device orientation %u", interfaceOrientation);
the value printed in console is 4- which is UIDeviceOrientationLandscapeRight.
So the interface orientation is UIInterfaceOrientationPortrait but device orientation is UIDeviceOrientationLandscapeRight.
One more thing, now if I rotate the device to portrait mode and then moving to landscape mode shows the correct landscape view and app starts behaving correctly.
So the problem is if I load the tab 3 in landscape mode it doesn't load properly
but if we enter in portrait mode and then rotate to landscape if works fine from thereon.
If anyone can give some useful suggestion why the behavior is like this that would be really beneficial.
Thanks
Add these lines to your Tab1 & Tab2 in viewWillAppear method,
#import <objc/message.h>
- (void)viewWillAppear:(BOOL)animated {
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation)){
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)]) {
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
}
Create a CustomTabBarController Class with Subclass of UITabBarController (for e.g: CustomTabBarController)
#interface CustomTabBarController : UITabBarController
Add the following lines to this class :
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
In your app delegate or where ever you are initializing UITabBarController, replace those instances with CustomTabBarController instances.
self.tabBarController = [[[CustomTabBarController alloc] init] autorelease];
Add the lines to your model view controllers with different view controller support:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotate {
return NO;
}
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;
}
Initially a subclass of UINavigationController (Navigator) is a root controller and it supports all orientations.
The subclass overrides supportedInterfaceOrientations and provides properties to set what orientation is supported.
The root view controller of Navigators navigation stack (subclass of UITableViewContreller) controls supported orientations (depending which view controller is on top of a stack). It sets Navigators orientation properties in the didSelectRowAtIndexPath override.
If a transition is made when a device is in different orientation (because current view does not support it and this is not a supposed way to interact) and new view supports that device orientation, the view remains in different orientation than the device orientation.
Then one needs to rotate the device and move it back to bring a proper orientation.
This is if someone for some reason would hold a device in landscape mode in Contacts App, but suddenly one of it's subviews would support landscape and rotate automatically without rotating device to portrait and then landscape. The question is how to implement it?
Use this in every method:
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight))
{
}
else
{
}
or check the [[UIScreen mainScreen] bounds]
I think this is want you want.
To get the device orientation:
[[UIDevice currentDevice] orientation];
To get the current orientation of the views showed:
[UIApplication sharedApplication].statusBarOrientation;
Add this method to your subclass of UINavigationController:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
return;
if ([UIViewController respondsToSelector:#selector(attemptRotationToDeviceOrientation)]) {
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[UIViewController alloc] init];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
}
(Found it here on SF, but cannot find a link to that question)
I have two view controller in my app.
1st view controller is portrait mode and 2nd view controller in landscape mode.
I don't want to change their orientation even when i rotate my iPhone.
How can i make?
In the Xcode, highlight the project in the Project Navigator, and select the target in the project tree. Open the Summary page, and go to the Supported Interface Orientations section. Un-click the orientations that you do not want your application to support.
In the story board, choose your first view controller, go to the Attributes inspector, and set orientation to "Portrait" in the Simulated Metrics section. Now choose the second view controller, and set its orientation to "landscape".
In the view controller code, implement
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
for the first view controller, and
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
for the second view controller. This should fix the problem for you.
In your case you have two VCs. So in both VC under below method just handle you orientations. and perform check against toInterfaceOrientation and return YES.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// For your VC1
if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
return YES;
// For your VC2
/*
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
return YES;
*/
}
I would like to control the device reorientation effect on two different UIViewControllers pushed onto a UINavigationController.
On the first view, I am setting my app to rotate to portait only, but seems it its doing it on all views.
This is the code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
And, on another view I am using the following code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
On my second view I would like to rotate to all orientations, only on the first i want the rotation to be restricted to portrait only.
Thanks!
I am working on an app (my first one), which is basically a TabBar app.
To be more precise there are:
- a login view controller
- a tab bar controller (when login is done)
- a landscape view controller that is used when the first itel of the TabBar is switch from Portrait to Landscape.
So, when I am in the first tab, I need to be able to move to landscape view to display some other data. In my tab bar controller, I have implemented those methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if([self selectedIndex] == 0)
return YES;
return NO;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// Get AppDelegate
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
// Remove TabBarView and add graph Landscape View
[self.view removeFromSuperview];
[delegate setSubViewLandscapeViewController];
}
}
In the delegate, I have implemented the setSubViewLandscapeViewController and the setSubViewTabBarController:
- (void)setSubViewTabBarViewController {
[window addSubview:[tabBarController view]];
}
- (void)setSubViewGraphLandscapeViewController {
[window addSubview:[landscapeViewController view]];
}
I want the landscapeViewController to display only in landscape mode, I have then (in my landscapeViewController):
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"willRotateToInterfaceOrientation");
}
A part of this works fine, I mean the switch from portrait to landscape is ok (when I am in the first tab), the tabbarcontroller is remove from the SuperView and the landscape view is added as a subview instead.
The thing is... I do not know how to switch back to portrait mode (and then load the previous controller, the tabBar one using the setSubViewTabBarViewController of my delegate). It seems none of the willRotateToOrientation, willRotateFromOrientation, .. are triggered when I actually move the device from the landscape view...
In short, when I am in the landscape view I do not know what to do to move back to the tabbar view... I am kind of stuck in the landscape view once I am in this one.
Thanks a lot for your help,
Luc
Look at the pie chart in CPTestApp-iPhone in the examples folder. It handles rotation by implementing -(void)didRotateFromInterfaceOrientation: and resizing the graph after a rotation.
Well, I managed to get a solution for this problem.
In fact, while moving from portrait to landscape I removed the tabbarcontroller from window subview and add the landscapeviewcontroller instead.
It seems it was not the correct thing to do.
Instead, I add the landscapeViewController as subview of the tabbarcontroller and remove it when going from landscape to portrait.
I still have a problem however with the y position of the landscape view which seems to changes when I do several decive rotation in a row....
Regards,
Luc