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;
*/
}
Related
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;
}
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
So in my app, I have a navigation stack, where the users can progress through a varity of viewControllers. Some of the views support multiple orientations, while one of the views does not. So my question is, how can I force one specific UIViewController to display only in one orientation. I need this to work both when the view loads for the first time, and when another view is popped off and this view to again visible. Thanks
I implement this two method to control the rotation of the views:
-(void)orientationDidChange:(NSNotification *)notification
-(BOOL)shouldAutoRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
Thanks
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Answer : shouldAutoRotateToInterfaceOrientation method of UIViewController Class.
This function returns YES if the orientations is supported by your UIView. If you return YES only to the landscape orientation, then the iPhone/iPad will automatically be put in that orientation whenever you load that view.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscape);
}
I have used UIDeviceOrientationDidChangeNotification to get notified of landscape and potrait mode. In my project I'm required to change the positions of UIControls placed on the UIView accordingly. Do I have to change the frame size manually for each UIControl, as this is hectic?
In your view controller you should implement method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
This method should return YES for supported orientations.
If you want your subviews to resize and reposition automatically then you should set appropriate property autoresizingMask of that views. For example:
blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
You do need to use the shouldAutorotateToInterfaceOrientation... method but you need to do a little more before it will work properly. First of all, you will need two xib files, one for a landscape orientation and one for a portrait orientation. You will then need to use your function like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft){
//prepare for a Landscape view
}
else{
//prepare for a portrait view
}
return YES;
}
As for preparing for landscape or portrait views, using autoresizing can work but you may need to have totally seperate xibs. I could not find a way to change the xib within the active view controller, so I would suggest making a seperate instance of your view controller. Example:
When you present your first instance of the viewController, present it with the portrait xib. You may also need a boolean to keep track of the current xib. Then have this code implemented:
/*Assuming you are using a viewcontroller called viewController, and you have a boolean called xibPortrait.
You have presented this view controller using the portrait xib.
You also have a landscape xib, Landscape.xib
*/
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ((interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft) && xibPortrait){
xibPortrait = FALSE;
viewController *Land = [[ViewController alloc] initWithNibName:#"Landscape" bundle:nil];
[self presentModalViewController:Land animated:NO];
[Land release];
}
else if(!xibPortrait){
[self.parentViewController dismissModalViewControllerAnimated:NO];
xibPortrait = TRUE;
}
return YES;
}
//This should work but if you can, you should try to use Autoresizing.
EDIT:
I also found this which someone posted on one of my questions. It may help your app work more efficiently than using my method above:
http://aseriesoftubes.com/articles/ipad-development-101-orientation/
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