I'd downloaded a sample from this tutorial site about rotating the viewcontrollers in navingation controllers.
That sample project functionality
Support potrait for FirstviewController
Support all orientations for second view controller(pushed from first VC)
What I need is,
FirstviewController should support all orientations
Second view controller(pushed from first VC) should support potrait alone.
What I did was, just swapped the codes in the view controllers
In first view controller
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
In Second view controller and
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
But, both the view controllers are rotating.
How can I fix this issue? Any suggestions, please share.
----EDIT----
If I rotate the simulator to landscape before pushing, second VC is also in landscape view.
If I push to second vc in potrait, the second VC is in potrait mode(it's not rotating if I rotate there.)
I put log in customNavigationcontroller NSLog(#"self.topViewController.class %#",self.topViewController.class);. It's only logging for firstview controller after pushing to second vc it's not logging
I suggest an easier way to solve this issue.
Select your project's target and configure it like this:
Then go to Appdelegate.m and paste:
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
// Handling UITabBarController
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
}
// Handling UINavigationController
else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
}
// Handling Modal views
else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
}
// Handling UIViewController's added as subviews to some other views.
else
{
for (UIView *view in [rootViewController.view subviews])
{
id subViewController = [view nextResponder]; // Key property which most of us are unaware of / rarely use.
if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
{
return [self topViewControllerWithRootViewController:subViewController];
}
}
return rootViewController;
}
}
Now here's the fun part.
Put this method on AppDelegate.m,you can decide the orientation of every controller here.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
id presentedViewController = [self topViewController];
NSString *className = presentedViewController ? NSStringFromClass([presentedViewController class]) : nil;
if (window && [className isEqualToString:#"FirstViewController"]) { //FirstviewController should support all orientations
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskPortrait; //Second view controller(pushed from first VC) should support potrait alone.
}
}
You can then remove all the other methods you've added such as shouldAutorotateToInterfaceOrientation, shouldAutorotate , supportedInterfaceOrientations , preferredInterfaceOrientationForPresentation.
All these methods are now all unnecessary.
-----Edit-----
Simply using
[[UIDevice currentDevice] setValue:[NSNumber numberWithInt:UIInterfaceOrientationPortrait] forKey:#"orientation"];
in all view controllers where I need potrait will do the trick. no other things needed.
Related
I'm new in Objective-C. I wanna fix portrait mode for specific view. Other view using landscape mode and put back portrait mode when finish the view. But, still landscape mode on specific view.
- (NSUInteger) supportedInterfaceOrientations {
// Return a bitmask of supported orientations. If you need more,
// use bitwise or (see the commented return).
return UIInterfaceOrientationMaskPortrait;
// return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;}
- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation {
// Return the orientation you'd prefer - this is what it launches to. The
// user can still rotate. You don't have to implement this method, in which
// case it launches in the current orientation
return UIInterfaceOrientationPortrait; }
I add the code to specific view.
[[UIDevice currentDevice] setValue:#(UIInterfaceOrientationLandscapeLeft) forKey:#"orientation"];
And then, this code input the method.
How can I modify to fix this?
It's really very easy.
Let's you have two ViewController class named 'ViewController' and 'SecondViewController'
First you have to import SecondViewController in 'AppDelegate' class.
Then copy and paste this two methods in your AppDelegate.m file
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if ([[self visibleViewController:[UIApplication sharedApplication].keyWindow.rootViewController] isKindOfClass:[SecondViewController class]]) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskLandscape;
}
and
- (UIViewController *)visibleViewController:(UIViewController *)rootViewController {
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self visibleViewController:lastViewController];
}
if ([rootViewController.presentedViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController.presentedViewController;
UIViewController *selectedViewController = tabBarController.selectedViewController;
return [self visibleViewController:selectedViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self visibleViewController:presentedViewController];
}
Now run and see.
I am trying to programmatically create UI orientation (portrait and landscape) using Objective C for all devices. Here the problem is I have multiple view controllers. I want to use multiple orientation into particular view controller.
For Ex:
Splash screen (App delegate - Portrait)
Login screen (Portrait)
Home screen (Both)
If I controlled by below method into App delegate root class then I cant enable both orientation into home view controller. Its showing black screen.
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskPortrait;
}
You can try by following implementation. What here doing is, we sends the interfaceorientation we need for the visible view controller from app delegate. For that fist finds the visible viewcontroler and gets its supported interface orientation, If supportedInterfaceOrientations method not implemented in the visible view controller, return default orientation.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
UIViewController *topController = [self topmostViewController];
if ([topController respondsToSelector:#selector(supportedInterfaceOrientations)]) {
return [topController supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (UIViewController *)topmostViewController {
UIViewController *topController = self.window.rootViewController;
return [self topViewControllerWithRootViewController:topController];
}
- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.topViewController];// dont use visible view controller, since it will return the presented ViewController, it may be UIAlertController.
} else if (rootViewController.presentedViewController && ![rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
And if you want to display any view controller with orientation other than UIInterfaceOrientationMaskAllButUpsideDown implement following method in your view controller
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return <whichever orientation you need>;
}
UPDATE:
Make sure that you selected only the orientations you needed for initial view controller in target settings.
Ref: Finding topmost view controller code from this answer with slight modification by addressing UIAlertcontroller presented case
I have an iOS app with 2 view controllers namely - FirstViewController and SecondViewController. My window's rootViewController is UINavigationController.
FirstViewController is supposed to work ONLY in portrait mode and SecondViewController ONLY in Landscape mode.
Searching all over Stackoverflow I found out that for iOS6 and above I have to create a category over UINavigationController and override -supportedInterfaceOrientations
THE PROBLEM
Starting from FirstViewController. Now my phone being in Portrait mode, I push SecondViewController, the view loads in portrait mode. Once I rotate my phone to be in landscape the view will rotate to landscape ( and from this point onwards will not return to portrait at all ).
When I pop back FirstViewController will be in Portrait again ( no matter what the orientation of the phone ).
I want that SecondViewController shouldn't be displayed in Portrait mode at all. I've racked my brains all day...cannot find a solution.
APPDELEGATE
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *vc = [[ViewController alloc] init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
[self.navigationController setNavigationBarHidden:YES];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
FirstViewController
- (IBAction)btnClicked:(id)sender
{
SecondViewController *vc = [[SecondViewController alloc] init];
[self.navigationController pushViewController:vc animated:NO];
}
#pragma mark - Rotation handlers
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
SecondViewController
- (IBAction)btnClicked:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - Rotation handlers
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
UINavigation Category
#implementation UINavigationController (Rotation)
-(BOOL)shouldAutorotate
{
//return [self.topViewController shouldAutorotate];
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
#end
Well, it's a bit late but here is what I figured.
While there are many solutions available for the case when FirstVC is Portrait and Second can be Portrait and Landscape, I couldn't find any good solution to this problem (First Portrait ONLY and Second Landscape ONLY). Here is what I did:
Embed both view controllers in their own Navigation Controllers. Create two new classes, say FirstNavController and SecondNavController subclassing UINavigationController. Use these as your navigation controllers. (If you are using StoryBoards, select the Navigation Controller, go to Identity Inspector and change 'Class' field).
Now, in FirstNavController, add:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
And in SecondNavController:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
You will have to present the SecondNavController modally.
Nothing needs to be done in your View Controllers. Make sure you add all required orientations in your application settings.
The only drawback of this method is that both views are not in the same navigation stack, as second was presented modally, so you won't see a back button. But you can add a cancel/dismiss button yourself and call dismissViewControllerAnimated in SecondVC.
in my previous app i have done it
first you need to enable Portrait , Landscape left , Landscape right Orientation to project
Now
set below code to your FirstViewController
-(void) viewWillAppear:(BOOL)animated{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
}
- (BOOL)shouldAutorotate
{
return NO;
}
set below code to your secondViewController
#define degreesToRadian(x) (M_PI * (x) / 180.0)
#implementation UINavigationController (Rotation_IOS6)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
#end
#interface secondViewController ()
#end
#implementation secondViewController
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
#end
I have iPhone application that supports only Portrait orientation. I want to add to my project view controller that will support only Landscape orientation? Is it possible? If yes how could I achieve that?
I have tried to crate category file like this:
#implementation UINavigationController (Rotation_IOS7)
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
If I do this I get this error:
Terminating app due to uncaught exception UIApplicationInvalidInterfaceOrientation, reason: Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES
I've tried this and it works: http://www.sebastianborggrewe.de/only-make-one-single-view-controller-rotate/
First, add these code to your AppDelegat class.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
// Get topmost/visible view controller
UIViewController *currentViewController = [self topViewController];
// Check whether it implements a dummy methods called canRotate
if ([currentViewController respondsToSelector:#selector(canRotate)]) {
// Unlock landscape view orientations for this view controller
return UIInterfaceOrientationMaskAllButUpsideDown;
}
// Only allow portrait (standard behaviour)
return UIInterfaceOrientationMaskPortrait;
}
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
Then, in your landscape view controller, add this method
- (void)canRotate { }
I have search through numerous topics and finally found a working solution.
In my example, I have two VC's:
A -> VC that is embedded inside Nav. Controller and should only support Portrait view.
B -> VC that is not embedded inside a VC and should support Landscape only.
I would like to go from view A to view B (by pressing a button) and back to view then A with the specific orientations still correct.
I. Create a Category for UINavigationController and write the following in its .m file: (the code will be automatically called)
- (NSUInteger)supportedInterfaceOrientations
{
NSLog(#"supportedInterfaceOrientations = %d ", [self.topViewController supportedInterfaceOrientations]);
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// You do not need this method if you are not supporting earlier iOS Versions
return [self.topViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
II.
Create a modal segue between A and B and after that between another one between B and A.
III. Write down in each of the View Controllers .m files the following:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
OR
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
After adding this code. You will be able to change orientation for the single view B.
Edit:
create a category in .h and then implement those methods
use these methods in the view controller where you want to support landscape
#implementation UINavigationController (Rotation_IOS7)
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
I have parent view controller and another modal view controller.
I presented modal view controller within parent's context:
readingViewController * reading_view_controller = [[readingViewController alloc] initWithNibName:#"readingViewController" bundle:nil];
[self setModalPresentationStyle:UIModalPresentationCurrentContext];
[self presentModalViewController:reading_view_controller animated:YES];
Parent viewController will not orient Landscape; so, i added these methods in the parent viewController:
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortraitUpsideDown|UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
The presented viewController (modally presented) should orient to all possible orientations; so, i added these methods:
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
But, because I assumed (UIModalPresentationCurrentContext), the presented viewController doesn't orient in IOS 6.0 while it is working as expected in IOS 5.0
How to solve this problem please?
If you have a tab-based app, then first add some code in app delegate and also self.window.rootviewcontroller-self.tabbarcontroller.
#implementation UITabBarController (SK8FASTR2App)
-(BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
// your custom logic for rotation of selected tab
if (self.selectedIndex==3){
return UIInterfaceOrientationMaskPortrait;
}
else {
UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown|UIInterfaceOrientationLandscapeLeft|UIInterfaceOrientationLandscapeRight;
return UIInterfaceOrientationMaskAll;
}
}
#end
before
#implementation AppDelegate
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskAll;
}
Change orientation on that class
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeRight;
}
You should implement
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation;
eg :-
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskAll;
}