iOS - 半透明模态视图控制器

25

我想以轻微透明的背景将一个视图控制器模态呈现在当前视图上,使得第一个视图在模态视图下略微可见。

我设置了模态视图控制器的alpha值,并将modalPresentationStyle设置为UIModalPresentationCurrentContext,正如另一篇文章中建议的那样。

结果是,当动画向上播放时,视图的背景是透明的,但当视图控制器到位时,背景会变成不透明的黑色。在解散时它又变回透明的。

我该怎么让它在活动时保持透明?

我已在中进行过测试。我正在使用以下代码:

MyModalViewController *viewController = [[MyModalViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navController setNavigationBarHidden:YES];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self.navigationController presentViewController:navController animated:YES completion:NULL];

5
使用 UIModalPresentationCurrentContext 在 iPhone 上无法实现此操作。在过渡后,背景中的控制器将被移除,这就是为什么所有东西都会消失的原因。如果你搜索一些例子,可以发现人们通过将屏幕截图保存为 UIImage,并将其用作模态控制器的背景来伪造此效果。 - Alex
3
亚历克斯说的是真的,你不能使用 IOS SDK 来做到那一点。这是一个类似问题和解决方法的链接:https://dev59.com/sXE85IYBdhLWcg3w2Hbs。 - Priyatham51
请查看我在另一篇帖子中的答案:http://stackoverflow.com/a/21381183/507323 - Alexis
https://dev59.com/Xs_Uz4gBFxS5KdRj4-Sg#22829068 - Zaraki
你可以在这里找到完整的解决方案:https://dev59.com/Xs_Uz4gBFxS5KdRj4-Sg#18949734 - malex
8个回答

42

iOS 8增加了一种专门用于此目的的新模态呈现样式:

presentedViewController.modalPresentationStyle = UIModalPresentationOverFullScreen

来自规范:

UIModalPresentationOverFullScreen

一种视图呈现样式,呈现的视图覆盖整个屏幕。当呈现结束时,位于呈现内容下方的视图不会从视图层次结构中移除。因此,如果呈现的视图控制器没有用不透明的内容填充整个屏幕,则可以看到底层内容。


4
这是正确的答案。现在我们要做的就是等待iOS 7的消失。 - Radu Simionescu
2
modalPresentationStyle 必须设置为被呈现的视图控制器,而不是呈现视图控制器。您可能需要相应地编辑答案中的变量。 - Theo

3

我也遇到了同样的问题。我通过查看以下关于自定义警告控制器的网址来解决它。我成功地使其在UINavigationController中运行。

Swift

let viewController = UIViewController()
viewController.providesPresentationContextTransitionStyle = true
viewController.definesPresentationContext = true
viewController.modalPresentationStyle = .overCurrentContext
viewController.modalTransitionStyle = .crossDissolve
DispatchQueue.main.async {
    self.navigationController?.present(viewController, animated: true, completion: nil)
}

Objective C

UIViewController *viewController = [UIViewController new];
viewController.providesPresentationContextTransitionStyle = true;
viewController.definesPresentationContext = true;
viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

dispatch_async(dispatch_get_main_queue(), ^{
    [self.navigationController presentViewController:viewController animated:true completion:nil];
});

3
如果您的目标是iOS 8及以上版本,则可以将模态呈现样式设置为“over current context”,这样就完成了。如果是iOS 7及以下版本,则需要创建自定义转换样式,以使呈现屏幕在转换后不会变空白,这相当复杂。
我提供的解决方案提供了很大的灵活性:在显示模态对话框之前截屏,并将其设置为应用程序窗口的背景图像。默认情况下,该背景为黑色(当返回视图控制器时看到的内容)。将背景更改为应用程序的屏幕截图。在透明视图的viewWillAppear或viewDidLoad方法中制作屏幕截图。这适用于推送segue,而不仅仅是模态对话框,但应避免动画效果。通常,避免影响背景视图位置的动画效果,因为这些动画在过渡结束时会使其似乎回到原位。最好在viewDidDissapear中将背景重置为先前的黑色图像,以避免产生不必要的影响。
您可以维护这种背景图像的堆栈,并进行多个“透明”推送序列。或者有一些复杂/深度菜单出现在某个主屏幕的顶部。由于这些原因,我认为这个解决方案比自己编写转换代码更好。它更加灵活易用,而且您不必自己处理动画效果。

2
BG视图控制器在显示模态视图后消失的原因是,iOS 7中默认的过渡动画完成后会移除BG视图。如果您定义自己的过渡动画,并将BG视图设置为不被移除(只更改其alpha值),那么您就可以拥有透明的模态视图。

1
FYI:现在的语法是:

    childVC.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen

1
我的解决方案是:
创建一个自定义的透明覆盖UIView,覆盖在任何视图、导航栏和选项卡上。
- 在包含您的视图控制器的导航控制器(或选项卡控制器)中,我创建了一个自定义视图,其框架等于导航控制器视图的框架。
- 然后,通过将其原点.y设置为navigationController.view.height,将其设置为屏幕外。
- 然后,我创建了两个函数-(void)showOverlay和-(void)hideOverlay,用于对覆盖视图进行动画处理。
- (void)hideOverlay{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3];

    CGRect frm = self.helpView.frame;//helpView is my overlay
    frm.origin.y = self.offscreenOffset; //this is an Y offscreen usually self.view.height
    self.helpView.frame = frm;

    [UIView commitAnimations];
}

- (void)showOverlay{

    [self.view bringSubviewToFront:self.helpView];

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3];

    CGRect frm = self.helpView.frame;
    frm.origin.y = self.onscreenOffset;
    self.helpView.frame = frm;

    [UIView commitAnimations];
}

在我的视图控制器中,我可以直接调用


[(MyCustomNavCtrl *)self.navigationController showOverlay];
[(MyCustomNavCtrl *)self.navigationController hideOverlay];

这大概就是它的全部内容了。

1

这里有一个解决方案。

创建你的展示视图控制器。在该视图控制器的主视图中添加一个后退视图。将其命名为backView

SecondViewController.m文件中

-(void)viewDidLoad
{
    // Make the main view's background clear, the second view's background transparent.
    self.view.backgroundColor = [UIColor clearColor];
    UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
    [self.view addSubview:backView];
}

现在您有一个带有半透明背景的视图控制器。您可以向self.view添加任何内容,其余部分将是半透明的。
之后,在FirstViewController.m中:
self.modalPresentationStyle = UIModalPresentationCurrentContext;

[self presentViewController:secondViewController animated:YES completion:nil];

1
但是,当第二个透明视图的模型动画完成后,它会立即将整个屏幕变成黑色! - Chanchal Raj

-2

为什么不尝试在AppDelegate中设置这个呢?

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

然后改变正在呈现的视图的alpha值


因为,正如我在问题中所述并在随后的讨论中提到的那样,这并不起作用。第一个视图控制器会在模态视图加载完成后立即被移除。 - Drew C
你尝试将它添加到AppDelegate了吗?你正在使用Storyboards吗? - Aaron Stephenson

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