my app doesn't support rotation. But I want to present a QLPreviewController that supports rotation.
I present the QLPreviewController like this:
[self presentModalViewController:thePrevController animated:NO];
How can I do this?
Enable all rotations in your application plist file. This will make all views rotate irrespective of the settings in the view controller.
Then subclass your root UINavigationController as below, adding the rotation control code for iOS5 and 6 depending on your requirements:
I was updating an old app with MainWindow.xib, so I changed the class of the navigation controller in the xib file to CustomNavigationController. But in a more modern app with say a main menu, you'd instantiate the nav controller like this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
MainMenuVC *masterViewController = [[MainMenuVC alloc] initWithNibName:#"MainMenuVC" bundle:nil];
self.navigationController = [[CustomNavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
Subclass UINavigationController
#import <UIKit/UIKit.h>
#interface CustomNavigationController : UINavigationController
#end
#import "CustomNavigationController.h"
#interface CustomNavigationController ()
#end
#implementation CustomNavigationController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate
{
return NO;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
#end
Then subclass the QLPreview controller so you can override the rotation code which will enable rotation for the QLPreviewController only. The rest of the app with views pushed from your CustomNavContoller will not rotate as the CustomNavigationController is locked.
I added this interface and implementation at the top of the view controller where I wanted to present the QLPreviewController.
#interface RotatingQLPreviewController : QLPreviewController
#end
#implementation RotatingQLPreviewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
-(BOOL)shouldAutorotate
{
return YES;
}
#end
Then present your QLPreviewController using your subclass.
RotatingQLPreviewController *preview = [[RotatingQLPreviewController alloc] init];
preview.dataSource = self;
[self presentViewController:preview
animated:YES
completion:^(){
// do more stuff here
}];
This method should work for other modal views that you want to rotate, but I haven't tried it.
I implemented this method in the latest app I'm working on and works in both iOS5 and 6.
Hope it helps.
Related
I have iPAD app which has UIViewController A as root view Controller of Navigation Controller.
Now i have 3 more View Controllers B,C, D as subview of ViewController A.
I want B not to respond orientation while C and D should respond to it.
Currently with code all of them respond to orientation change.
There was another answer which says make two separate root ViewControllers and add them into windows View. One of them non rotating and other rotating. I cant do that because i have header in ViewController A which switches B,C,D to make them front viewController.
Anyway please suggest.
Thanks
You need to subclass the UINavigationController like this.
.H
#import <UIKit/UIKit.h>
#interface UINavigationController (Rotation)
- (BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
.M
#import "UINavigationController+Rotation.h"
#implementation UINavigationController (Rotation)
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([self visibleViewController] && [[self visibleViewController] isKindOfClass:[B class]]) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
#end
You can create subclass from UINavigationController or make category for it. And implement this methods:
-(BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
And then, in your controllers you should implement this methods with orientations which you want.
So I have the following hierarchy:
UINavigationController --> RootViewController (UIViewController) --> UITableViewController --> DetailViewController (UIViewController)
I want to lock the orientation on RootViewController to Portrait only, but leave all orientations for the rest view controllers.
If I put this to subclassed UINavigationController:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
All view controllers are then locked to portrait.
My question is, is there a way to lock only RootViewController to Portrait, but leave all options for other view controllers?
check the link here for fixing autorotation in iOS 6 and set orientation support per view basis: http://www.disalvotech.com/blog/app-development/iphone/ios-6-rotation-solution/
Here is what you could do:
Create a custom navigation controller that is a subclass of UINavigationController, in your .m file:
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
In your AppDelegate.h,
#interface AppDelegate : UIResponder <UIApplicationDelegate> {
UINavigationController *navigationController;
ViewController *viewController;
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
and in AppDelegate.m,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// set initial view
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewController = [[ViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
navigationController = [[CustomNavigationController alloc]
initWithRootViewController:viewController]; // iOS 6 autorotation fix
[navigationController setNavigationBarHidden:YES animated:NO];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:navigationController]; // iOS 6 autorotation fix
//[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window // iOS 6 autorotation fix
{
return UIInterfaceOrientationMaskAll;
}
in your rootViewController, for whatever the event push the second view controller, do this:
- (IBAction)pushSecondViewController:(id)sender {
// push second view controller
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
}
in your each view controller, add
- (BOOL)shouldAutorotate{}
- (NSUInteger)supportedInterfaceOrientations{}
for iOS 6, you can set each view controller whatever the orientation support you want individually.
for iOS 5 and below, you can set
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{}
All the credits goes to John DiSalvo who wrote the sample app in the link.
Hope this helps.
in singleton
-(void)setOrientationSupport:(BOOL)flag{
flag_orientationSupport_ = flag;
}
-(BOOL)getOrientationSupport{
return flag_orientationSupport_;
}
in appdelegate
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([singleton getOrientationSupport])
return UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
}
add the following code in viewwillappear
for the viewcontroller you want support orientation
[singleton setOrientationSupport:YES];
to those controller you want disable orientation
[singleton setOrientationSupport:NO];
Put this in your Nav controller:
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
Now, add this to your root view controller:
- (BOOL)shouldAutorotate
{
return NO;
}
That should do it!
To delegate the responsibility of defining allowed orientations to subviews of a UINavigationController, one can use the visibleViewController property of the nav controller to make the navigation controller "ask" it's child views for their supported orientations. The following code should work (Swift) :
Sub-classed navigation controller:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if let visibleView = self.visibleViewController {
return visibleView.supportedInterfaceOrientations()
} else {
return UIInterfaceOrientationMask.All
}
}
Sub-view (root view) of nav controller:
// Restrict to portrait
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
I have been searching for the solution for hours!
So after implementing the needed methods everywhere. shouldAutorotate doesn't need to be set to YES because it is already set as default:
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
When it is time to show the UIViewController which needs the orientation different than the other views, I created a UIStoryboardSegue with this implementation inside:
#import "Showing.h"
#implementation Showing
- (void)perform{
NSLog(#"Showing");
UIViewController *sourceVC = self.sourceViewController;
UIViewController *presentingVC = self.destinationViewController;
[sourceVC.navigationController presentViewController:presentingVC
animated:YES
completion:nil];
}
#end
Inside the UIStoryboard I connected the views with this segue (showing):
It is just important, you are using
presentViewController:animated:completion:
AND NOT
pushViewController:animated:
otherwise the orientation won't be determined again.
I had been trying things like
[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
OR this one inside the UIViewController where the orientation should change, and I also tryied to call it inside my custom UIStoryboardSegues before presentingViewController and dismissViewController:
[UIViewController attemptRotationToDeviceOrientation];
OR
NSNumber *numPortrait = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:numPortrait forKey:#"orientation"];
But no one of them worked. Of course the last example shouldn't be an option, because if apple will change anything of their api this could cause problems inside your app.
I also tried to use the AppDelegate method and always determine the orientation inside this method after looking for the correct UIInterfaceOrientation of the actual visibleViewController but then it sometimes happened to crash when switching from one to another orientation. So I'm still wondering why its made so complicated and there seems also not to be any documentation where it is explained correctly.
Even following this part didn't help me.
I have set UIInterfaceOrientationMaskAll in supportedInterfaceOrientations method.
When I present UIModalViewController I always get dimensions of the view 748 x 1024 regardless of the screen rotation. If I rotate the screen, dimensions does not get updated and are the same in portrait and landscape mode: 748 x 1024.
This is the code to present modal view:
MyModalViewController *myModal = [[MyModalViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:myModal animated:YES];
MyModalViewController extends another MyCUSTOMViewController which is a subclass of UIViewController:
#interface MyModalViewController : MyCUSTOMViewController
#interface MyCUSTOMViewController : UIViewController
What am I doing wrong?
From what I have read there are a couple of things to consider:
To make other orientations available throughout the app, you must override -(NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window within the app’s UIApplicationDelegate, and return UIInterfaceOrientationMaskAll:
In your custom viewcontroller you need to override two methods:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
am creating a application which is support all type of orientation, i added one UIView on the UIWindow.but on rotating the device the view which is added on the Window is not rotating. the view always showing default (Portrait). please help me to fix this problem ...
Thanks in advance
You need to add a UIViewController on your UIWindow.
UIView doesn't handle rotations, UIViewController does.
So, all you need is to create a UIViewController, which implements shouldAutorotateToInterfaceOrientation and sets this controller as a rootViewController to your UIWindow
Something like that:
- (void) makeWindow
{
UIViewController * vc = [[[MyViewController alloc] init] autorelease];
UIWindow * window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setRootViewController:vc];
[window makeKeyAndVisible];
}
#interface MyViewController : UIViewController
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
//your view initialization here
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
#end
I have an app with some views, I need one view to rotate. that view is called by pushviewcontroller. all these views are inside a tabbarcontroller.
I already edit the info.plist to support orientations I added this items to Supported interface orientations:
Landscape (left home button)
Landscape (right home button)
and also added this to the view i want to rotate
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
but it doesnt work.
what do i need to do? Thanks
UITabBarController have a some problem. the problems is a subviews(selected index) not autorotate.
So, you can make a category, and add a below code.
and, add a #import "UITabBarController+Autorotate.h"
#import <Foundation/Foundation.h>
#interface UITabBarController (Autorotate)
#end
#import "UITabBarController+Autorotate.h"
#implementation UITabBarController (Autorotate)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
UIViewController *controller = self.selectedViewController;
if ([controller isKindOfClass:[UINavigationController class]])
controller = [(UINavigationController *)controller visibleViewController];
return [controller shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
#end