I have a view controller that contains an image and a tableview. From this view controller I connected a segue to a landscape view that contains the image in full screen (same idea used when you turn sideways the Stocks app from Apple to see the graph in full screen).
This segue is called by the following method:
- (void)updateLandscapeView
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
[self performSegueWithIdentifier: #"toGraph" sender: self];
isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
[self dismissViewControllerAnimated:YES completion:nil];
isShowingLandscapeView = NO;
}
}
Besides this, when the iphone is at portrait orientation, I can also drill-down the tableview a couple more levels. The problem is the following: at those consequent levels, the segue to the landscape view still gets triggered when I turn the orientation to landscape!... what can I do so that this does not happen? I am only interested in going to landscape mode from the first view which contains the image.
Thank You in advance!
I don't know for sure if I got your issue right.. but if you mean with "drill-down the table view" to go deeper in a navigation controller hierachy, you can try the following..
That's what I did in a (I think) similar situation:
AppDelegate:
in .h:
#property (nonatomic) BOOL shouldAutorotate;
in .m:
// in didFinishLaunchingWithOptions:
self.shouldAutorotate = NO;
// still in .m file
// Autorotation handling
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return self.shouldAutorotate ?
UIInterfaceOrientationMaskAllButUpsideDown :
UIInterfaceOrientationMaskPortrait;
}
Navigation Controller presenting Portrait Controller
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSUInteger)supportedInterfaceOrientations
{
if (self.selectedViewController)
return [self.selectedViewController supportedInterfaceOrientations];
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate
{
return YES;
}
Portrait View Controller (here's also a very similar segue handling that you have):
in viewWillAppear:
[(AppDelegate *)[[UIApplication sharedApplication] delegate] setShouldAutorotate:YES];
rotation handling:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Landscape View Controller (probably your full screen image):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Deeper in the navigation controller hierachy (where only portrait is wanted):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Looks somehow complicated, but that was the only way, I managed to get those rotation things working properly in both iOS5 and 6.
Related
I used this code to block the rotation before ios 7 (i was also using xibs, now storyboard)
- (BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationPortrait;
}
now that i migrated to storyboard and ios7 it is not working, my view is still rotating.
UPDATE:
I solved this by adding this code to the delegate, now my previous code works like charm
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
if (self.fullScreenVideoIsPlaying) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
else {
if(self.window.rootViewController){
UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
orientations = [presentedViewController supportedInterfaceOrientations];
}
return orientations;
}
Atrik's code worked. Here is a more complete solution which allows locking and unlocking of portrait-mode-only even with the use of UINavigationController
appdelegate .h
#property (nonatomic) BOOL screenIsPortraitOnly;
appdelegate .m
#pragma mark - View Orientation
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
if (self.screenIsPortraitOnly) {
return UIInterfaceOrientationMaskPortrait;
}
else {
if(self.window.rootViewController){
UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
orientations = [presentedViewController supportedInterfaceOrientations];
}
return orientations;
}
}
For all view controllers where I need Portrait Lock
If you haven't used a subclass which has the app delegate imported then don't forget to import the delegate. For most view controllers I use a subclass of UIViewController which at least does importation.
#import "AppDelegate.h"
I use this for all portrait locked viewcontrollers.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:true];
[self portraitLock];
}
-(void) portraitLock {
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
appDelegate.screenIsPortraitOnly = true;
}
#pragma mark - interface posiiton
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL) shouldAutorotate {
return NO;
}
ViewDidLoad runs before viewDidAppear so I run this in my subclass of UIViewController to unlock all screens. The viewWillAppear with the lock method is used only in the cotrollers which I need to lock the screen.
- (void)viewDidLoad
{
[super viewDidLoad];
[self portraitUnLock];
}
-(void) portraitUnLock {
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
appDelegate.screenIsPortraitOnly = false;
}
If you only want in landscape mode then you can do it with xcode project setting
go to Target > summary > support interface orientations
Or you can do a code
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (UIInterfaceOrientationIsLandscape(interfaceOrientation));
}
In XCode 5, which is required to be used for iOS7 development, you can go to your target and under Deployment Info uncheck everything except Portrait for device orientation.
If you don't want your app to rotate at all (no matter which view is active), you can click on your project in the Xcode sidebar, scroll down, and deselect Landscape Left and Landscape Right.
I have an app which has 2 view controllers. The first viewcontroller should be in portrait and it's ok, but when I'm loading the second view controller, I could not make the app orientation to be landscape... The problem is with iOS 6.
I have tried everything I found on SO.
Using [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO]; on viewWillAppear and viewDidLoad,
and also:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
} else {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
}
-(BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
-(NSInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeRight;
}
Add these code in 2nd View Controller's viewDidLoad method to transform view into landscape :
[self rotateController:self degrees:-90];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];
//set it according to 3.5 and 4.0 inch screen in landscape mode
[self.view setBounds:CGRectMake(0, 0, 480, 320)];
add rotateController method :
-(void) rotateController:(UIViewController *)controller degrees:(NSInteger)aDgrees
{
UIScreen *screen = [UIScreen mainScreen];
if(aDgrees>0)
controller.view.bounds = CGRectMake(0, 0, screen.bounds.size.height, screen.bounds.size.width);
else
{
controller.view.bounds = CGRectMake(0, 0, screen.bounds.size.width, screen.bounds.size.height);
}
controller.view.transform = CGAffineTransformConcat(controller.view.transform, CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(aDgrees)));
}
Now in viewWillDisappear's method to transform view into protrait . Add these:
[self rotateController:self degrees:90];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
//set it according to 3.5 and 4.0 inch screen in protrait mode
[self.view setBounds:CGRectMake(0, 0, 320, 480)];
Also your orientation methods should be like these if not added add these :
- (BOOL)shouldAutorotate
{
//make view landscape on start
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
EDIT : Add these macro for radian
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
you may add this code on this view controller where you want to fix your orientation
Code as Below
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
return UIInterfaceOrientationMaskPortrait;
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
return (toInterfaceOrientation==UIInterfaceOrientationPortrait);
}
}
and second view controller you may want to rotate all orientation then not necessary to adding any code ios6 will manage the orientation automatically.
You need to select the landscape mode in application summary-> deployment info.
Also if you are using xib file to design the UI, you need to set the orientation of second view controller to landscape
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
-(NSInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
You were not returning the NO in the method shouldAutorotate , replace you existing code with this .
Hope it will help you.
Prior to iOS 6 i.e in iOS 5 and earlier, an app and a view controller’s rotation is controlled by the individual viewcontrollers while in iOS 6 and later, the view controllers responsible for rotation are the container Viewcontrollers such as UINavigationController & UITabBarController . What are you using as the rootviewcontroller in your project??
Autorotation is clearly explained here in this post- Autorotation in iOS
the orientation methods have changed in iOS 6.
my whole app in portrait mode got to many view controllers (not tab bar view controllers) i just want to rotate one of my view controller to landscape mode (it actually displays a webView) when i rotate the device.the below method was working in xcode 4.4 but, it's not in Xcode.4.5
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight );
the above method won't work in xcode 4.5 for this reason i have changed the below method but even though its not working....plz any suggestions thanks.
- (BOOL) shouldAutorotate{
[[UIApplication sharedApplication] setStatusBarOrientation: UIInterfaceOrientationPortrait];
return self.modalViewController.shouldAutorotate;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Do you use tab bar view controller? If you use it, then all view controllers in all tabs should be able to rotate even if you only want to rotate only one.
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
This should work fine in iOS6.
If you use UINavigationViewController, then its methods would be called. There is another solution.
// App delegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;
if(self.window.rootViewController){
UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
orientations = [presentedViewController supportedInterfaceOrientations];
}
return orientations;
}
And then in view controllers
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
So I have a view that I present modally when the interface orientation changes to landscape. However when the orientation returns to portrait and the modal view dismisses itself, the tableview from the initial view remains in landscape orientation (this table view must be only in portrait orientation)
Here is the code :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return ((interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight) );
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
[self performSegueWithIdentifier:#"showCatChart" sender:self];
}
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
[self refreshTableView];
}
}
I tried to refresh the tableview but that doesn't make it portrait again ...
this could be from the view hierachy ...
NavigationController->tableView (only portrait)->tableview->landscapeViewModalController
With iOS 6, you need to implement the following:
- (BOOL)shouldAutoRotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
In your AppDelegate, you need to change the following:
[self.window addSubview:viewController.view];
to
[self.window setRootViewController:viewController];
Also, keep your current code if you want to support previous versions of iOS.
Use the following in appdelegate.
[self.window addsubview:viewcontroller];
This alone will solve your orientation problem.
So I have a UITableViewControler displaying a tableview in portrait mode.
As soon as i rotate the iPhone i want to present a modal view in landscape mode.
In the tableView i use:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
And to handle the present the modal view:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval)duration {
if((interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft))
{
NSLog(#"Push page view");
PagingViewController *s = [[PagingViewController alloc] initWithNibName:#"PagingView" bundle:nil];
s.hidesBottomBarWhenPushed = YES;
[self presentModalViewController:s animated:YES];
[s release];
}
}
The modal view i have the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
And to dismiss the modal view it self, I do:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval)duration {
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
NSLog(#"Dismiss my self");
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
}
Some how this works two times.
The third time i rotate the iPhone from Portrait mode to Landscape mode, i get a bad access error.
I cant figure out what gives me the error.
Anyone care for a shot?
The simplest way I can think of is to implement -shouldAutorotate... and dismiss the modal view and return NO to abort rotation. Perhaps that will be sufficient to avoid any concurrency issues. If this suggestion isn't to your liking take a look at NSNotificationCenter.