在UIViewController上面显示另一个UIViewController时如何设置背景透明。

155

我有一个作为另一个UIViewController视图子视图/模态而存在的UIViewController视图,使得子视图/模态应该是透明的,并且添加到子视图的任何组件都应该可见。问题在于,子视图显示为黑色背景而不是clearColor。我正在尝试将UIView设置为clearColor而不是黑色背景。有人知道问题出在哪里吗?任何建议都会受到赞赏。

FirstViewController.m

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];

[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentModalViewController:vc animated:NO];  

SecondViewController.m

- (void)viewDidLoad 
{
     [super viewDidLoad];
     self.view.opaque = YES;
     self.view.backgroundColor = [UIColor clearColor];
}

已解决:我修复了问题。现在无论是iPhone还是iPad都可以非常好地使用没有黑色背景的模态视图控制器,只需使用clearColor/transparent即可。唯一需要更改的是我将UIModalPresentationFullScreen替换为UIModalPresentationCurrentContext。多么简单!

FirstViewController.m

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];

注意:如果您正在使用navigationControllermodalPresentationStyle属性:

FirstViewController.m

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
vc.view.backgroundColor = [UIColor clearColor];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:NO completion:nil];

注意:不好的消息是,上面的解决方案在iOS 7上不起作用。好消息是,我已经为iOS 7修复了这个问题!我向某人寻求帮助,他给出了以下建议:

当以模态方式呈现视图控制器时,iOS会从视图层次结构中删除其下面的视图控制器,以便在其呈现期间使用。虽然您模态呈现的视图控制器的视图是透明的,但除了应用程序窗口(黑色)之外,下面没有任何内容。 iOS 7引入了一种新的模态呈现样式UIModalPresentationCustom,它使iOS不会删除呈现的视图控制器下面的视图。但是,为了使用此模态呈现样式,您必须提供自己的转换委托来处理呈现和解除动画。在“使用视图控制器进行自定义转换”WWDC 2013演讲中,概述了如何实现自己的转换委托。链接地址:https://developer.apple.com/wwdc/videos/?id=218

您可以在iOS 7中查看我针对上述问题的解决方案:https://github.com/hightech/iOS-7-Custom-ModalViewController-Transitions


1
请确保设置rootViewController的modalPresentationStyle,否则它将无法工作。 - Thorsten
请看一下这个答案的评论https://dev59.com/Xs_Uz4gBFxS5KdRj4-Sg#25990081,它有效。 - onmyway133
这个问题(https://dev59.com/Sobca4cB1Zd3GeqPT0kK)让我开心,现在轮到你了 :) - Hemang
我必须在被呈现的视图控制器中使用self.modalPresentationStyle = UIModalPresentationCurrentContext;才能使其正常工作,而不是在呈现的视图控制器中使用。 - Tulleb
2
请查看下面的Brody的答案。modalViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext; 将解决这个问题。 - GoodSp33d
我曾经卡在这里,直到我明白 modalPresentationStyle 属性必须在呈现视图控制器之前设置:(Swift)presentedViewController.modalPresentationStyle = .overCurrentContext; self.present(presentedViewController, animated: true, completion: nil) - Laurent Maquet
16个回答

148

iOS8+

iOS8+现在可以使用新的modalPresentationStyle UIModalPresentationOverCurrentContext来呈现具有透明背景的视图控制器:

MyModalViewController *modalViewController = [[MyModalViewController alloc] init];
modalViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;           
[self presentViewController:modalViewController animated:YES completion:nil];    

5
应该选择这个答案作为被接受的答案。先前被接受的答案由于传统原因仍然有效,但这是推荐的方法。 - Tomasz Bąk
3
如果您只是为iOS 8进行开发,请使用这个答案!它能够正常工作。 - Mário Carvalho
2
这很好,但是最后一行应该是 [self presentViewController:modalViewController animated:YES completion:nil]; 吗?(而不是 targetController)? - SuperDuperTango
4
为了让这个对我起作用,我添加了 modalViewController.view.backgroundColor = UIColor.clearColor() ,感谢解决方案。 - Pramod
有人能提供给我pushviewcontroller的代码吗?(我的意思是针对导航控制器) - Alok
显示剩余4条评论

142

已解决:我修复了这些问题。现在无论是在iPhone还是iPad上都能正常工作,模态视图控制器没有黑色背景,只需使用clearColor/transparent即可。唯一需要更改的是我将UIModalPresentationFullScreen替换为UIModalPresentationCurrentContext。多么简单!

FirstViewController.m

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    vc.view.backgroundColor = [UIColor clearColor];
    self.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:vc animated:NO completion:nil];

注意:如果您正在使用navigationController的modalPresentationStyle属性:

FirstViewController.m

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    vc.view.backgroundColor = [UIColor clearColor];
    self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:vc animated:NO completion:nil];

注意:坏消息是,以上解决方案在iOS 7上不起作用。好消息是,我为iOS 7修复了这个问题!我向某人求助并得到以下回答:

当以模态方式呈现视图控制器时,iOS会在呈现期间从视图层次结构中删除其下面的视图控制器。 当您模态呈现的视图控制器的视图是透明的时候,除应用程序窗口外,下面没有任何东西。应用程序窗口是黑色的。iOS 7引入了一种新的模态呈现样式,UIModalPresentationCustom,可使iOS不删除呈现的视图控制器下面的视图。但是,为了使用此模态呈现样式,您必须提供自己的转换代理来处理呈现和解除动画。 这在WWDC 2013的“使用视图控制器进行自定义转换”演讲中有概述 https://developer.apple.com/wwdc/videos/?id=218,该演讲还介绍了如何实现自己的过渡代理。

您可以在以下链接找到我在iOS7中针对上述问题的解决方案:https://github.com/hightech/iOS-7-Custom-ModalViewController-Transitions


1
self.modalPresentationStyle = UIModalPresentationCurrentContext; 完成了。 - lucasart
4
顺便说一下,我观察到由于 self.modalPresentationStyle = UIModalPresentationCurrentContext; 的缘故,模态视图控制器没有以动画形式呈现.. 有任何想法吗? - Devarshi
1
在iOS 6和7中运行此代码时,新的视图控制器在呈现动画期间是透明的,但一旦它到位后,背景会变成黑色。当执行消失动画时,它又会变成透明的。还有其他人遇到过这个问题吗? - Drew C
3
我更新了适用于iOS 7的解决方案。希望这能帮到你。原文链接:https://dev59.com/pWgu5IYBdhLWcg3wkHyP#11252969。 - hightech
1
刚在iOS 8上测试了一下。只需将modalPresentationStyle更改为UIModalPresentationCustom即可解决问题(隐藏黑色背景并不会移除其他视图)。我认为没有必要实现GitHub项目中的TransitionDelegate.h/m和AnimatedTransitioning.h/m类。 - RyJ
显示剩余11条评论

115

对于纯视觉思维者和故事板爱好者,您可以进行以下操作:

1. 呈现视图控制器

定义上下文

2. 被呈现的视图控制器

展示:超过当前上下文


这应该是被接受的答案。你只需要这样做就可以了,然后将模态控制器视图的背景颜色设置为透明。 - Jesse
同意,在这种情况下,故事板选项会覆盖代码。 - C0D3
17
这个回答真是太甜了,我现在得了糖尿病。 - GeneCode

26

Swift 3和iOS10的解决方案:

//create view controller
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "RoadTripPreviewViewController")
//remove black screen in background
vc.modalPresentationStyle = .overCurrentContext
//add clear color background
vc.view.backgroundColor = UIColor.clear
//present modal
self.present(vc, animated: true, completion: nil)

16

这是来自使用控制拖动转场的xCode 7 beta 4。只需将目标背景设置为透明,并在IB中将segue属性设置为此值(注意:Presentation也可以是“Over Full Screen”):

输入图像描述


2
谢谢。我按照@pasevin的建议进行了Segue修复和ViewControllers答案,现在它可以正常工作了! - CSawy
1
这回答了我的问题。非常感谢。点个赞 :D - Nate4436271

8

我发现在iOS7和iOS8上让它工作的最简单方法是在modallyPresentedVC(你想要以模态方式呈现的视图控制器)上设置presentationStyle为UIModalPresentationOverCurrentContext,这是由于iOS8的原因:

[modallyPresentedVC setModalPresentationStyle:UIModalPresentationOverCurrentContext];
[modallyPresentedVC.navigationController setModalPresentationStyle:UIModalPresentationOverCurrentContext];

由于iOS7的原因,需要在presentingVC(即呈现模态表现的控制器)上使用UIModalPresentationFullScreen而不是UIModalPresentationCurrentContext:
[presentingVC setModalPresentationStyle:UIModalPresentationCurrentContext];
[presentingVC.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext];

由于iOS7和iOS8的处理方式不同。当然,如果您没有使用导航控制器,则不必设置导航控制器属性。希望这有所帮助。


5

Swift2 版本:

let vc = self.storyboard!.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController
vc.view.backgroundColor = UIColor.clearColor()
vc.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen // orOverCurrentContext to place under navigation
self.presentViewController(vc, animated: true, completion: nil)

4
对我来说,这个很有效:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil];
    UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"MMPushNotificationViewController"];

    vc.view.backgroundColor = [UIColor clearColor];
    self.modalPresentationStyle = UIModalPresentationCurrentContext;
#ifdef __IPHONE_8_0
    if(IS_OS_8_OR_LATER)
    {
        self.providesPresentationContextTransitionStyle = YES;
        self.definesPresentationContext = YES;
        [vc setModalPresentationStyle:UIModalPresentationOverCurrentContext];
    }
#endif


    [self presentViewController:vc animated:NO completion:nil];

MMPushNotificationViewController 是透明的视图控制器,我还将 MMPushNotificationViewController 的视图颜色设置为 clearcolor。现在,我已经完成了所有工作,并使我的透明视图控制器。


4

iOS 7自定义过渡动画解决方案:

CustomSegue.h
#import <UIKit/UIKit.h>

    @interface CustomSegue : UIStoryboardSegue <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>

    @end



CustomSegue.m
#import "CustomSegue.h"

@implementation CustomSegue

-(void)perform {

    UIViewController* destViewController = (UIViewController*)[self destinationViewController];
    destViewController.view.backgroundColor = [UIColor clearColor];
    [destViewController setTransitioningDelegate:self];
    destViewController.modalPresentationStyle = UIModalPresentationCustom;
    [[self sourceViewController] presentViewController:[self destinationViewController] animated:YES completion:nil];
}


//===================================================================
// - UIViewControllerAnimatedTransitioning
//===================================================================

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

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {

    UIView *inView = [transitionContext containerView];
    UIViewController* toVC = (UIViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController* fromVC = (UIViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    [inView addSubview:toVC.view];

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    [toVC.view setFrame:CGRectMake(0, screenRect.size.height, fromVC.view.frame.size.width, fromVC.view.frame.size.height)];

    [UIView animateWithDuration:0.25f
                     animations:^{

                         [toVC.view setFrame:CGRectMake(0, 0, fromVC.view.frame.size.width, fromVC.view.frame.size.height)];
                     }
                     completion:^(BOOL finished) {
                         [transitionContext completeTransition:YES];
                     }];
}


//===================================================================
// - UIViewControllerTransitioningDelegate
//===================================================================

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {

    return self;
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    //I will fix it later.
    //    AnimatedTransitioning *controller = [[AnimatedTransitioning alloc]init];
    //    controller.isPresenting = NO;
    //    return controller;
    return nil;
}

- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator {
    return nil;
}

- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator {
    return nil;
}

@end

基于高科技代码的解决方案。

当我使用 [self dismissViewControllerAnimated:YES completion:NULL]; 关闭时,我会收到一个异常? - Asadullah Ali
对于这段代码,是的。或者你需要实现animationControllerForDismissedController方法来启动动画工作。 - Max Gribov

4

另一种方法(无需创建自定义的过渡效果,适用于iOS 7)

使用Storyboard:

创建可自由调整大小的子视图控制器,将视图宽度设置为500x500(例如),并添加以下方法:

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    self.view.superview.bounds = CGRectMake(0, 0, 500, 500);
    self.view.superview.backgroundColor = [UIColor clearColor];
}

然后创建一个带有表单样式的Modal 转场,并进行测试。

你太棒了!!!这真的起作用了!!!(在IB中设置“自由”大小不会影响任何东西,因为它是模拟指标,但无论如何,它起作用了!!!)而且它很简单!!! - Radu Simionescu

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