25

I have an application that is configured via the plist file to support portrait, landscape left, and landscape right orientations (i.e. UISupportedInterfaceOrientations is set to UIInterfaceOrientationPortrait, UIInterfaceOrientationLandscapeLeft, and UIInterfaceOrientationLandscapeRight). But I've limited the supported orientations to just portrait inside of a view controller. If I present a UIActionSheet on the view controller's view and then rotate the device, the UIActionSheet rotates to the new orientation. This only happens on devices running iOS 8 (GM Seed).

I would like the UIActionSheet to follow the rules of the containing view controller and not rotate. Thoughts?

I don't want this to happen: screenshot

UIViewController Sample Code:

- (IBAction)onTouch:(id)sender
{
    UIActionSheet * actionSheet = [[UIActionSheet alloc] initWithTitle:@"hi"
                                                       delegate:nil
                                              cancelButtonTitle:@"Cancel"
                                         destructiveButtonTitle:nil
                                              otherButtonTitles:@"Open", nil];

    [actionSheet showInView:self.view];
}

#pragma mark - Rotation methods

- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Awesomeness
  • 652
  • 1
  • 8
  • 14

5 Answers5

21

Here is my workaround based on the solution from Busrod with some modifications because I had some problems in UIActionSheet using his workaround:

-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *presentedViewController = window.rootViewController.presentedViewController;
    if (presentedViewController) {
        if ([presentedViewController isKindOfClass:[UIActivityViewController class]] || [presentedViewController isKindOfClass:[UIAlertController class]]) {
            return UIInterfaceOrientationMaskPortrait;
        }
    }
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
Praveen-K
  • 3,401
  • 1
  • 23
  • 31
StuckOverFlow
  • 851
  • 6
  • 15
11

I had a similar problem with iOS 8 and found a workaround that may help if you want to stick with UIAlertView and UIActionSheet for now, instead of migrating to UIAlertController.

My app allows Landscape and Portrait, but only on select views. Most of the time it only allows Portrait. I want UIAlertView and UIActionSheet to appear only Portrait (because the views they are on only allow Portrait).

Unfortunately, with iOS 8 the alerts and action sheets now rotate, ignoring the shouldAutorotate method of the window's root view controller. The view and status bar underneath the alert stay visible in Portrait even if the alert rotates. If the alert takes an input, the keyboard also stays Portrait, so it is really unattractive.

I was about to give up, but finally found something that works, even if it is not ideal. Put this in your app delegate, and adapt as needed. I'm looking forward to a better solution (probably just using the new classes). String comparison here is obviously lame, and this will override whatever you have set as supported orientation in Info.plist. At least it is something to go on...

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    NSString *viewControllerClassName = [NSString stringWithUTF8String:object_getClassName(window.rootViewController)];
    if ([viewControllerClassName isEqualToString:@"_UIAlertShimPresentingViewController"])   {
        return UIInterfaceOrientationMaskPortrait;
    }
    else {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    }
}

Read more about this delegate here:

https://developer.apple.com/library/prerelease/iOS/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:supportedInterfaceOrientationsForWindow:

Bushrod
  • 417
  • 3
  • 7
  • Will this result in an App Store rejection since it is using a private class? – sethfri Oct 06 '14 at 19:04
  • If you're worried about "_UI...", try user3750435's variation below. "Using" the class name to determine when not to rotate isn't the safest thing, but shouldn't be a violation as it isn't calling any method/property of the class. As another alternative, you could match the window to your own known window. My use is enterprise only so no risk of rejection. – Bushrod Oct 07 '14 at 20:01
5

Was informed that UIAlertController replaces UIActionSheet in iOS 8.

"The new UIAlertController class replaces the UIActionSheet and UIAlertView classes as the preferred way to display alerts in your app."

https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"hi"
                                                                          message:nil
                                                                   preferredStyle:UIAlertControllerStyleActionSheet];

[alertController addAction:[UIAlertAction actionWithTitle:@"Open"
                                                  style:UIAlertActionStyleDefault
                                                handler:^(UIAlertAction *action) {
                                                   // open something
                                                }]];

[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel"
                                                  style:UIAlertActionStyleCancel
                                                handler:nil]];

[self presentViewController:alertController animated:YES completion:nil];
Awesomeness
  • 652
  • 1
  • 8
  • 14
  • 5
    Sure, there is a new "preferred" way, but why change/break old working functionality just because a new way is introduced? Is this new way the only way to get the original behavior? – Bushrod Sep 18 '14 at 19:04
  • No, because iOS7 users still have to deal with the old alert/sheets. Clearly a bug that need fixing. – Morrowless Sep 25 '14 at 04:27
  • 2
    On iOS7 the old UIActionSheet does not exhibit the rotation issue. Use UIActionSheet on iOS7 and older. Use UIAlertController on iOS8 and newer. Check for NSClassFromString(@"UIAlertController") to determine which code to use. – Awesomeness Oct 05 '14 at 14:13
  • @ChitraKhatri I add an example of how to use UIAlertController to the post above. – Awesomeness Oct 27 '14 at 21:08
0

Adding to @user3750435 's answer

Since the OP has defined the rotation masks he/she wants in the Info.plist, we do not need to redefine the masks here. UIApplication can return us those masks via supportedInterfaceOrientationsForWindow:. So, the method can be made simpler like this:

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *presentedViewController = window.rootViewController.presentedViewController;
    if (presentedViewController) {
        if ([presentedViewController isKindOfClass:[UIActivityViewController class]] || [presentedViewController isKindOfClass:[UIAlertController class]]) {
            return UIInterfaceOrientationMaskPortrait;
        }
    }
    return [application supportedInterfaceOrientationsForWindow:window];
}
Ayush Goel
  • 3,134
  • 27
  • 36
0

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

UIViewController *presentedViewController = window.rootViewController.presentedViewController;
if (presentedViewController) {
    if ([presentedViewController isKindOfClass:[UIActivityViewController class]] || [presentedViewController isKindOfClass:[UIAlertController class]]) {
        return UIInterfaceOrientationMaskPortrait;
    }
}
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;

}

thanks this worked for me