呈现透明半透明视图控制器,在iOS7和iOS8上均可正常工作

15

我有下面这段代码,在iOS7上运行得非常完美。

[UIView animateWithDuration:0.5 animations:^(void) {
    self.view.alpha = 0.5;
    [self.navigationController.navigationBar setAlpha:0.3];

}]; //to make the background view controller semi-transparent
UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
[rootViewController setModalPresentationStyle:UIModalPresentationCurrentContext];
OverlayViewController *ctlr = [storyBoard instantiateViewControllerWithIdentifier:@"OverlayViewController"];
//present the OverlayViewController
[self presentViewController:ctlr animated:YES completion:nil];

然后我在背景视图控制器的viewWillAppear方法中添加了以下内容,将其视图恢复为完全不透明。

[UIView animateWithDuration:1.0 animations:^(void) {
    self.view.alpha = 1.0;
    [self.navigationController.view setAlpha:1.0];
}];

在 iOS8 中,以上代码无法将背景设置为半透明。黑色颜色会围绕 OverlayViewController。

我在网上发现了使用 UIModalPresentationOverCurrentContext 将会得到期望的行为。实际上确实是这样的,但是背景视图控制器永远不会从视图层级中删除 (编辑以添加对此行为的参考:https://developer.apple.com/documentation/uikit/uimodalpresentationstyle)。所以,viewWillAppear 永远不会被调用,因此半透明永远不会被移除。

显然,我可以诉诸于使用 NSNotificationCenter 等 hack 方法,并在 OverlayViewController 被移除时触发通知,但这感觉像是一个迂回的方式来完成应该简单的事情。是否有其他方法优雅地实现这一点呢?

相关问题:

1)如果 UIModalPresentationOverCurrentContext 是实现这一点的唯一方法,那么我想知道是否会被迫放两个版本的代码,以使其在 iOS7 和 iOS8 中都能正常工作。

2)很明显,旧版 Xcode 不认识这个新枚举类型。那么,我的团队应该升级到 Xcode 6,以确保他们可以运行这段代码,即使他们的其他工作只集中在 iOS7 上?还是有办法告诉旧版本的 Xcode 忽略仅针对 iOS8 需要的特定代码块呢?

3个回答

36

你需要处理iOS 7和iOS8的两个配置。在这两种情况下,您需要确保背景视图控制器不被从视图层次结构中删除。可以通过以下方式实现:

  1. 在iOS7上,通过为呈现视图控制器设置modalPresentationStyle标志为UIModalPresentationCurrentContext来完成此操作。您需要确定谁是呈现视图控制器:如果您有多个容器视图控制器,则不一定是self.navigationController

  2. 在iOS8上,通过将呈现视图控制器的modalPresentationStyle标志设置为UIModalPresentationOverCurrentContext来完成此操作。如果您正在使用Storyboard,请确保演示文稿样式设置为Storyboard Segue的默认值,并在prepareForSegue方法中将演示文稿样式设置为目标视图控制器为UIModalPresentationOverCurrentContext

现在回答您的相关问题:

1)您需要编写代码来处理iOS7和iOS8上的两种情况:

定义一些宏以检查应用程序正在运行的版本号。例如,以下内容将执行此操作:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

2)显然,如果您有需要在iOS7和iOS8上编译的代码,那么您的团队需要升级到最新版本的XCode"截至目前为止为XCode 6.1。


谢谢。讲解得很清楚!我们最终做了与您在这里描述的非常相似的事情。不幸的是,我没有足够的声望来点赞您的回答。 - Shankar
请确保故事板Segue的演示样式设置为默认值 - 谢谢,这让我解决了问题。 - Bat Lanyard

4
在iOS 8.x的Swift中:
UIModalPresentationStyle.OverCurrentContext设置为被呈现的viewController即可完成任务。
    func presentTransparentController(){
        var viewController = self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerNamed") as! ViewController

        // set to .OverCurrentContext
        viewController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext

        // presents the view controller as usual
        self.presentViewController(viewController, animated: true, completion: nil)
    }

1
非常感谢你,亲爱的Marco,你救了我的一天。 - Imran Sh

1
基于 @Tiguero 的答案,我创建了一个小的分类类来解决这个问题。
@implementation UIViewController (Extensions)

- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    if(SYSTEM_VERSION_LESS_THAN(@"8.0")) {
        self.parentViewController.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
    }else{
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    }

    [self presentViewController:viewControllerToPresent animated:YES completion:completion];
}

@end

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