iOS 8 UIActionSheet无视视图控制器的supportedInterfaceOrientations和shouldAutorotate属性

25

我有一个应用程序,通过plist文件进行配置以支持纵向、左横向和右横向方向(即UISupportedInterfaceOrientations设置为UIInterfaceOrientationPortrait、UIInterfaceOrientationLandscapeLeft和UIInterfaceOrientationLandscapeRight)。但是在视图控制器中,我将支持的方向限制为仅支持纵向。如果我在视图控制器的视图上呈现UIActionSheet,然后旋转设备,UIActionSheet会旋转到新的方向。这只会发生在运行iOS 8(GM Seed)的设备上。

我希望UIActionSheet遵循包含视图控制器的规则而不旋转。您有什么想法吗?

我不希望出现以下情况:screenshot

UIViewController示例代码:

- (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;
}
5个回答

21

这里是我的解决方法,基于Busrod的解决方案进行了一些修改,因为我在使用他的解决方法时遇到了一些UIActionSheet上的问题:

-(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;
}

是的,这个可以。谢谢! 如果可用,我选择使用新的UIAlertController。块的使用非常好,我很快就会放弃iOS 7支持。 - Awesomeness
2
这会导致竖屏倒置失败。 - Vignesh
如果您想支持倒置屏幕,返回UIInterfaceOrientationMaskAll。 - Ben H
对于SLComposeViewController也有同样的问题,可以在if语句中添加。 - Igor Palaguta

11

我之前在 iOS 8 上遇到类似的问题,但找到了一个解决方法,如果您现在想继续使用UIAlertView和UIActionSheet而不是迁移到UIAlertController,这可能会有所帮助。

我的应用程序允许横屏和竖屏,但仅限于某些视图。大部分时间它只允许竖屏。我希望UIAlertView和UIActionSheet仅以竖屏显示(因为它们所在的视图仅允许竖屏)。

不幸的是,在iOS 8中,警报和操作表现在会旋转,忽略窗口根视图控制器的shouldAutorotate方法。即使警报旋转,警报下面的视图和状态栏仍保持竖屏可见。 如果警报需要输入,则键盘也会保持竖屏,因此它看起来非常不美观。

我差点放弃了,但最终找到了一些有效的方法,即使不完美也可以解决问题。将以下代码放入应用程序委托中,并根据需要进行适应。我期待更好的解决方案(可能只需使用新的类)。在这里进行字符串比较显然很糟糕,而且这将覆盖您在Info.plist中设置的支持方向。不过至少这是一个可行的方法...

-(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;
    }
}

阅读有关该代表的更多信息:

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


这会导致应用商店拒绝吗,因为它使用了私有类? - sethfri
如果你担心"_UI...",可以尝试使用user3750435下面的变体。使用类名来确定何时不旋转并不是最安全的方法,但不应该违反任何类的方法/属性调用。另一种选择是将窗口匹配到自己已知的窗口。我的使用仅限于企业,因此没有被拒绝的风险。 - Bushrod

5

据了解,在iOS 8中,UIAlertController取代了UIActionSheet。

"新的UIAlertController类取代了UIActionSheet和UIAlertView类成为在应用程序中显示警报的首选方式。"

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];

5
当然,有一种新的“首选”方式,但为什么要改变/破坏旧的可行功能,只因为引入了一种新的方式呢?这种新方式是得到原始行为的唯一方法吗? - Bushrod
不行,因为iOS7用户仍然必须处理旧的警报/表单。显然这是需要修复的错误。 - Morrowless
2
在iOS7上,旧的UIActionSheet没有旋转问题。在iOS7及更早版本上使用UIActionSheet。在iOS8及更高版本上使用UIAlertController。检查NSClassFromString(@“UIAlertController”)以确定要使用哪个代码。 - Awesomeness
@ChitraKhatri 我在上面的帖子中添加了如何使用UIAlertController的示例。 - Awesomeness

0

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

- (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;

}

谢谢,这对我有用


0

补充@user3750435的答案

由于OP已经在Info.plist中定义了他/她想要的旋转掩码,因此我们不需要在这里重新定义掩码。UIApplication可以通过supportedInterfaceOrientationsForWindow:返回给我们这些掩码。因此,该方法可以简化为:

-(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];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接