190

我正在尝试以模态方式呈现具有透明背景的视图控制器。我的目标是让呈现和呈现的视图控制器的视图同时显示。问题是,当呈现动画完成时,呈现视图控制器的视图消失了。

- (IBAction)pushModalViewControllerButtonPressed:(id)sender
{
    ModalViewController *modalVC = [[ModalViewController alloc] init];
    [self presentViewController:modalVC animated:YES completion:nil];
}

我知道我可以将视图添加为子视图,但出于某种原因我想避免使用此解决方案。我该如何解决?

4

24 回答 24

192

对于那些试图让它在 iOS 8 中工作的人来说,“Apple 认可”的显示透明模式视图控制器的方法是modalPresentationStyle 在当前ed控制器上设置为 UIModalPresentationOverCurrentContext.

这可以在代码中完成,也可以通过在故事板中设置 segue 的属性来完成。

从 UIViewController 文档:

UIModalPresentationOverCurrentContext

仅在父视图控制器的内容上显示内容的演示样式。演示结束时,所呈现内容下方的视图不会从视图层次结构中删除。因此,如果呈现的视图控制器没有用不透明的内容填充屏幕,则底层内容会显示出来。

在弹出窗口中呈现视图控制器时,仅当过渡样式为 UIModalTransitionStyleCoverVertical 时才支持此呈现样式。尝试使用不同的转换样式会触发异常。但是,如果父视图控制器不在弹出窗口中,您可以使用其他转换样式(部分卷曲转换除外)。

在 iOS 8.0 及更高版本中可用。

https://developer.apple.com/documentation/uikit/uiviewcontroller

WWDC 2014 中的“iOS 8 中的视图控制器改进”视频对此进行了详细介绍。

笔记:

  • 一定要给你呈现的视图控制器一个清晰的背景颜色,以免它实际上不是透明的!
  • 您必须在呈现之前viewDidLoad设置此参数,即在presentedViewController 中设置此参数不会有任何影响
于 2014-09-23T08:09:59.810 回答
110

在 iOS 8.0 及更高版本中,可以通过将属性modalPresentationStyle设置为UIModalPresentationOverCurrentContext来完成

//Set property **definesPresentationContext** YES to avoid presenting over presenting-viewController's navigation bar

self.definesPresentationContext = YES; //self is presenting view controller
presentedController.view.backgroundColor = [YOUR_COLOR with alpha OR clearColor]
presentedController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

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

见附图

于 2015-01-12T19:40:30.193 回答
106

以下代码仅适用于 iPad。

self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalVC animated:YES];

我会添加一个子视图。

这是一个很好的讨论。具体看评论。不仅仅是答案。

模态视图

如果我是你,我不会这样做。我会添加一个子视图并执行此操作。它似乎让我可以更好地控制事情。

编辑:

正如 Paul Linsay 所提到的,从 iOS 8 开始,所需要UIModalPresentationOverFullScreen的只是呈现 ViewController 的 modalPresentationStyle。这也将涵盖 navigationBar 和 tabBar 按钮。

于 2012-10-05T07:12:35.377 回答
44

此代码在 iOS6 和 iOS7 下的 iPhone 上运行良好:

presentedVC.view.backgroundColor = YOUR_COLOR; // can be with 'alpha'
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];

在这种情况下,您会错过滑入式动画。要保留动画,您仍然可以使用以下“非优雅”扩展:

[presentingVC presentViewController:presentedVC animated:YES completion:^{
    [presentedVC dismissViewControllerAnimated:NO completion:^{
        presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
        [presentingVC presentViewController:presentedVC animated:NO completion:NULL];
    }];
}];

如果我们的presentingV 位于UINavigationController 或UITabbarController 内部,您需要将该控制器作为presentingVC 进行操作。

此外,在 iOS7 中,您可以实现自定义过渡动画应用UIViewControllerTransitioningDelegate协议。当然,在这种情况下,您可以获得透明背景

@interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate>

首先,在演示之前,您必须设置modalPresentationStyle

modalViewController.modalPresentationStyle = UIModalPresentationCustom;

然后你必须实现两个协议方法

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    CustomAnimatedTransitioning *transitioning = [CustomAnimatedTransitioning new];
    transitioning.presenting = YES;
    return transitioning;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
    CustomAnimatedTransitioning * transitioning = [CustomAnimatedTransitioning new];
    transitioning.presenting = NO;
    return transitioning;
}

最后一件事是在CustomAnimatedTransitioning类中定义您的自定义转换

@interface CustomAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic) BOOL presenting;
@end

@implementation CurrentContextTransitionAnimator

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext 
{
    return 0.25;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext 
{
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    if (self.presenting) {
        // custom presenting animation
    }
    else {
        // custom dismissing animation
    }
}
于 2013-09-22T23:16:55.950 回答
21

我在 XCode 7 的 Interface Builder 上有点挣扎,以按照@VenuGopalTewari 的建议设置 Presentation Style。在这个版本中,segue 似乎没有Over Current ContextOver Full Screen演示模式。因此,为了使其工作,我将模式设置为Default

在此处输入图像描述在此处输入图像描述

此外,我将模态呈现的视图控制器的呈现模式设置为Over Full Screen

在此处输入图像描述

于 2015-10-14T10:26:24.297 回答
19

创建一个 segue 以模态方式呈现,并将该 segue 的 Presentation 属性设置为超过当前上下文,它将 100 % 工作

在此处输入图像描述

于 2015-01-21T18:38:32.170 回答
16

使用 swift 对此答案的解决方案如下。

let vc = MyViewController()
vc.view.backgroundColor = UIColor.clear // or whatever color.
vc.modalPresentationStyle = .overCurrentContext
present(vc, animated: true, completion: nil)
于 2017-07-06T16:21:39.820 回答
14

具有透明背景的 PresentViewController - 在 iOS 8 和 iOS 9 中

MYViewController *myVC = [self.storyboard   instantiateViewControllerWithIdentifier:@"MYViewController"];
    myVC.providesPresentationContextTransitionStyle = YES;
    myVC.definesPresentationContext = YES;
    [myVC setModalPresentationStyle:UIModalPresentationOverCurrentContext];
    [self.navigationController presentViewController:myVC animated:YES completion:nil];

并在 MYViewController 中设置背景颜色为黑色并降低不透明度

于 2016-06-23T08:06:01.107 回答
12

这有点老套,但对我来说,这段代码有效(iOS 6):

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

[self presentViewController:self.signInViewController animated:YES completion:^{
    [self.signInViewController dismissViewControllerAnimated:NO completion:^{
        appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
        [self presentViewController:self.signInViewController animated:NO completion:nil];
        appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;

    }];
}];

此代码也适用于 iPhone

于 2013-09-24T11:29:40.873 回答
11

这个类别对我有用(ios 7、8 和 9)

H文件

@interface UIViewController (navigation)
- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;
@end

文件

@implementation UIViewController (navigation)
- (void)presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    if(SYSTEM_VERSION_LESS_THAN(@"8.0")) {
        [self presentIOS7TransparentController:viewControllerToPresent withCompletion:completion];

    }else{
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
         [self presentViewController:viewControllerToPresent animated:YES completion:completion];
    }
}
-(void)presentIOS7TransparentController:(UIViewController *)viewControllerToPresent withCompletion:(void(^)(void))completion
{
    UIViewController *presentingVC = self;
    UIViewController *root = self;
    while (root.parentViewController) {
        root = root.parentViewController;
    }
    UIModalPresentationStyle orginalStyle = root.modalPresentationStyle;
    root.modalPresentationStyle = UIModalPresentationCurrentContext;
    [presentingVC presentViewController:viewControllerToPresent animated:YES completion:^{
        root.modalPresentationStyle = orginalStyle;
    }];
}
@end
于 2015-09-08T16:11:02.827 回答
10

如果您使用 Storyboard,则可以按照以下步骤操作:

  1. 添加视图控制器 (V2),按照您想要的方式设置 UI
  • 添加一个 UIView - 将背景设置为黑色,不透明度设置为 0.5
  • 添加另一个 UIView(2) - 将作为您的弹出窗口(请注意 UIView 和 UIView(2) 必须具有相同的级别/层次结构。不要使 imageview 成为视图的子视图,否则 uiview 的不透明度将影响 UIView(2))
  1. 模态呈现 V2

  2. 单击转场。在属性检查器中,将 Presentation 设置为Over Full Screen。如果你喜欢删除动画

故事板

  1. 选择 V2。在属性检查器中,将 Presentation 设置为Over Full Screen。检查定义上下文并提供上下文

故事板

  1. 选择您的 V2 的 MainView(请检查图像)。将 backgroundColor 设置为清除颜色

故事板

于 2017-09-20T03:24:06.237 回答
7

我在呈现的视图控制器的 init 方法中添加了这三行代码,效果非常好:

self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self setModalPresentationStyle:UIModalPresentationOverCurrentContext];

编辑(在 iOS 9.3 上工作):

self.modalPresentationStyle = UIModalPresentationOverFullScreen;

根据文档:

UIModalPresentationOverFullScreen 一种视图呈现样式,其中呈现的视图覆盖屏幕。演示结束时,所呈现内容下方的视图不会从视图层次结构中删除。因此,如果呈现的视图控制器没有用不透明的内容填充屏幕,则底层内容会显示出来。

在 iOS 8.0 及更高版本中可用。

于 2016-03-31T08:52:38.137 回答
4

另一种方法是使用“容器视图”。只需将 alpha 设为 1 以下并嵌入 sequ。XCode 5,针对 iOS7。在 iPhone 上测试。

在此处输入图像描述

iOS6 提供的容器视图。 链接到有关此的博客文章。

于 2013-08-14T09:46:56.117 回答
4

我创建了一个对象来处理我所谓的“叠加模式”的呈现,这意味着它保留了背景的视图并允许您拥有一个具有透明背景的模式。

它有一个简单的方法可以做到这一点:

- (void)presentViewController:(UIViewController *)presentedViewController
       fromViewController:(UIViewController *)presentingViewController
{
    presentedViewController.modalPresentationStyle = UIModalPresentationCustom;
    presentedViewController.transitioningDelegate = self;
    presentedViewController.modalPresentationCapturesStatusBarAppearance = YES;

    [presentedViewController setNeedsStatusBarAppearanceUpdate];

    [presentingViewController presentViewController:presentedViewController
                                       animated:YES
                                     completion:nil];
}

如果您呈现的视图控制器具有不同modalPresentationCapturesStatusBarAppearance的.YESpreferredStatusBarStyle

这个对象应该有一个@property (assign, nonatommic) isPresenting

您希望此对象遵守UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate协议并实现以下方法:

- (id)animationControllerForPresentedController:(UIViewController *)presented
                           presentingController:(UIViewController *)presenting
                               sourceController:(UIViewController *)source
{
    self.isPresenting = YES;

    return self;
}

- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
    self.isPresenting = NO;

    return self;
}

和:

- (NSTimeInterval)transitionDuration:(id)transitionContext
{
    return 0.25;
}

- (void)animateTransition:(id)transitionContext
{
    UIViewController* firstVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* secondVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView* containerView = [transitionContext containerView];
    UIView* firstView = firstVC.view;
    UIView* secondView = secondVC.view;

    if (self.isPresenting) {
        [containerView addSubview:secondView];
        secondView.frame = (CGRect){
            containerView.frame.origin.x,
            containerView.frame.origin.y + containerView.frame.size.height,
            containerView.frame.size
        };

        firstView.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
        [UIView animateWithDuration:0.25 animations:^{
            secondView.frame = containerView.frame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
        } else {
        [UIView animateWithDuration:0.25 animations:^{
            firstView.frame = (CGRect){
                containerView.frame.origin.x,
                containerView.frame.origin.y + containerView.frame.size.height,
                containerView.frame.size
        };

        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
}

这是一个从底部滑入的动画,模仿默认的模态动画,但您可以随意制作。

重要的是呈现视图控制器的视图将保留在后面,让您创建透明效果。

此解决方案适用于 iOS 7+

于 2014-11-27T16:52:46.173 回答
3

一个非常简单的方法(Storyboards例如使用 )是:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SomeStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SomeStoryboardViewController"];
// the key for what you're looking to do:
vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
vc.view.alpha = 0.50f;

[self presentViewController:vc animated:YES completion:^{
    // great success
}];

这将以模态方式呈现 a UIViewControllerStoryboard但具有半透明背景。

于 2016-01-14T16:19:38.453 回答
3

为 iOS 7-10 工作

if #available(iOS 8.0, *) {
    nextVC.modalPresentationStyle = .OverCurrentContext
    self.presentViewController(nextVC, animated: true, completion: nil)
} else {
    // Fallback on earlier version
    self.modalPresentationStyle = .Custom          
    nextVC.modalTransitionStyle = .CrossDissolve            
    self.presentViewController(nextVC, animated: false, completion: nil)
    }
}
于 2017-03-15T12:42:40.277 回答
2

在这里回顾所有好的答案和评论,并在移动到新的时仍然有动画,ViewController这就是我所做的:(支持 iOS 6 及更高版本)

如果您使用UINavigationController\UITabBarController这是要走的路:

    SomeViewController *vcThatWillBeDisplayed = [self.storyboard instantiateViewControllerWithIdentifier:@"SomeVC"];

    vcThatWillBeDisplayed.view.backgroundColor = [UIColor colorWithRed: 255/255.0 green:255/255.0 blue:255/255.0 alpha:0.50];    

    self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:presentedVC animated:YES completion:NULL];

如果你这样做,你将失去你的modalTransitionStyle动画。为了解决它,您可以轻松地将其添加到您的SomeViewController课程中:

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIView animateWithDuration:0.4 animations:^() {self.view.alpha = 1;}
       completion:^(BOOL finished){}];
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.alpha = 0;
}
于 2014-07-09T14:10:48.840 回答
2

当然你应该设置 UIModalPresentationCurrentContext,但是设置 clearColor 的地方也很重要!您不能在 viewDidLoad 函数中设置背景,在视图加载之前设置它,就像在根视图控制器或将要呈现的控制器的init 函数中一样!

actionController.view.backgroundColor = [UIColor clearColor];
[self presentViewController:actionController animated:YES completion:nil];

或者

- (instancetype)init {

    self = [super initWithNibName:nil bundle:nil];

    if(self) {
        self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
        [self.view setBackgroundColor:[UIColor clearColor]];
    }

    return self;
}
于 2018-12-06T02:14:57.453 回答
1

如果您使用的是模态转场,请确保将其设置为此图像(如果您愿意,可以关闭动画)在此处输入图像描述

于 2014-12-17T05:20:33.427 回答
1

在 iOS 7 和 iOS 8 上测试的完整方法。

@interface UIViewController (MBOverCurrentContextModalPresenting)

/// @warning Some method of viewControllerToPresent will called twice before iOS 8, e.g. viewWillAppear:.
- (void)MBOverCurrentContextPresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;

@end

@implementation UIViewController (MBOverCurrentContextModalPresenting)

- (void)MBOverCurrentContextPresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    UIViewController *presentingVC = self;

    // iOS 8 before
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
        UIViewController *root = presentingVC;
        while (root.parentViewController) {
            root = root.parentViewController;
        }

        [presentingVC presentViewController:viewControllerToPresent animated:YES completion:^{
            [viewControllerToPresent dismissViewControllerAnimated:NO completion:^{
                UIModalPresentationStyle orginalStyle = root.modalPresentationStyle;
                if (orginalStyle != UIModalPresentationCurrentContext) {
                    root.modalPresentationStyle = UIModalPresentationCurrentContext;
                }
                [presentingVC presentViewController:viewControllerToPresent animated:NO completion:completion];
                if (orginalStyle != UIModalPresentationCurrentContext) {
                    root.modalPresentationStyle = orginalStyle;
                }
            }];
        }];
        return;
    }

    UIModalPresentationStyle orginalStyle = viewControllerToPresent.modalPresentationStyle;
    if (orginalStyle != UIModalPresentationOverCurrentContext) {
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    }
    [presentingVC presentViewController:viewControllerToPresent animated:YES completion:completion];
    if (orginalStyle != UIModalPresentationOverCurrentContext) {
        viewControllerToPresent.modalPresentationStyle = orginalStyle;
    }
}

@end
于 2015-03-10T06:26:50.740 回答
1

斯威夫特 4.2

guard let someVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "someVC") as? someVC else {
    return
}
someVC.modalPresentationStyle = .overCurrentContext

present(someVC, animated: true, completion: nil)
于 2019-04-15T19:14:49.173 回答
0

在 appdelegate 中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[_window rootViewController]setModalPresentationStyle:UIModalPresentationCurrentContext];
    return YES;
}

在您必须加载下一个视图的第一个视图控制器中:

  NextViewController *customvc = [[NextViewController alloc]init];
    [self presentViewController:customvc animated:YES completion:^{

    }];

在要添加透明的 nextViewController 中:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor clearColor];
    UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
    [self.view insertSubview:backView atIndex:0];
}
于 2014-04-03T06:02:00.347 回答
0

登录屏幕是一个模式,这意味着它位于前一个屏幕的顶部。到目前为止,我们已经模糊了背景,但它并没有模糊任何东西;它只是一个灰色的背景。

我们需要正确设置我们的模态。

图片链接目标

  • 首先,我们需要将 View Controller 的 View 背景更改为 Clear color。它只是意味着它应该是透明的。默认情况下,该视图是白色的。

  • 其次,我们需要选择通向登录屏幕的 Segue,并在 Attribute Inspector 中,将 Presentation 设置为 Over Current Context。此选项仅在启用自动布局和大小类的情况下可用。

图片链接目标

于 2015-04-15T07:05:50.220 回答
0

将导航设置modalPresentationStyleUIModalPresentationCustom

并将您呈现的视图控制器的背景颜色设置为清晰的颜色。

于 2017-07-05T08:28:31.570 回答