如何使用presentModalViewController创建透明视图


80

我正在显示一个模态视图

[self presentModalViewController:controller animated:YES];

当视图在屏幕上移动时,根据创建它的xib文件中的设置是透明的,但是一旦填充屏幕,它就会变得不透明。

无论如何,要保持视图透明?

我怀疑正在放置的视图没有被渲染,而是模态视图变得不透明。


1
这个问题现在已经很老了。寻找答案时,请寻找适用于您使用的iOS版本的答案。
Darryl Braaten 2014年

这个stackoverflow.com/q/27598846/1603234让我微笑,现在轮到您了:)
Hemang 2014年

您可以使用viewcontroller.modalPresentationStyle = .FormSheet
杰拉尔德

Answers:


63

您的视图仍然是透明的,但是一旦您的模式控制器位于堆栈的顶部,它后面的视图就会被隐藏(任何最顶部的视图控制器都是这种情况)。解决方案是自己手动创建视图动画。那么the-viewController就不会被隐藏(因为您将不会“离开”它)。


谢谢,这证实了我的怀疑。
Darryl Braaten

1
我已就此问题向Apple提交了错误报告。打开雷达:openradar.appspot.com/radar?id=1062402
理论

4
问题在于呈现的视图不能具有自己的自动旋转设置。
Shizam 2013年

85

在iOS 3.2之后,有一种方法可以做到这一点而没有任何“技巧” –请参阅modalPresentationStyle属性的文档。您有一个将显示viewController的rootViewController。因此,这是成功的代码:

viewController.view.backgroundColor = [UIColor clearColor];
rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[rootViewController presentModalViewController:viewController animated:YES];

使用此方法,viewController的背景将是透明的,而底层的rootViewController将是可见的。请注意,这似乎仅在iPad上有效,请参阅下面的评论。


1
Hi .. +1从我身边bcoz在iOS 4和iPad中正常工作。但它如何在iPhone 3.0中运行。感谢
Mitesh Khatri

3
它不适用于我(iOS 5.0),有人可以显示一些代码吗?
丹尼尔(Daniel)

6
这似乎不适用于iPhone / iPod,仅适用于iPad(请参阅答案中链接的文档)。@simpleBob:也许这就是为什么它对您不起作用?
2012年

1
FYI:我已要求在这个岗位同样的问题:stackoverflow.com/questions/14419395/...
疯狂的黑猩猩

1
我在iOS 8上进行了测试,并且必须使用它Over Current Context作为演示样式。
haxpor

48

我需要什么来使其工作:

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

1
简单的作品,谢谢,我只是不停地在我的代码- (BOOL)申请:(UIApplication的*)应用程序didFinishLaunchingWithOptions:(NSDictionary的*)launchOptions方法,瞧
Kshitiz吉米雷

2
您也可以只modalPresentationStyle在当前视图控制器上(而不是在窗口的上rootViewController)设置。
mbinna 2013年

谢谢!!甚至可以在您执行此操作时使用[self performSegueWithIdentifier:@“ open” sender:self];
DogCoffee

您始终可以在模态的viewdidload中手动为视图设置动画。
雅各布·K

2
请注意,如下文T先生所述,必须在当前具有全屏显示的视图控制器上设置modalPresentationStyle。
jessepinho

24

对于那些想看一些代码的人,这是我添加到透明视图的控制器中的内容:

// Add this view to superview, and slide it in from the bottom
- (void)presentWithSuperview:(UIView *)superview {
    // Set initial location at bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, superview.bounds.size.height);
    self.view.frame = frame;
    [superview addSubview:self.view];            

    // Animate to new location
    [UIView beginAnimations:@"presentWithSuperview" context:nil];
    frame.origin = CGPointZero;
    self.view.frame = frame;
    [UIView commitAnimations];
}

// Method called when removeFromSuperviewWithAnimation's animation completes
- (void)animationDidStop:(NSString *)animationID
                finished:(NSNumber *)finished
                 context:(void *)context {
    if ([animationID isEqualToString:@"removeFromSuperviewWithAnimation"]) {
        [self.view removeFromSuperview];
    }
}

// Slide this view to bottom of superview, then remove from superview
- (void)removeFromSuperviewWithAnimation {
    [UIView beginAnimations:@"removeFromSuperviewWithAnimation" context:nil];

    // Set delegate and selector to remove from superview when animation completes
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    // Move this view to bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, self.view.superview.bounds.size.height);
    self.view.frame = frame;

    [UIView commitAnimations];    
}

我对这个解决方案唯一的问题是内存管理。例如:TestViewController * testView = [[TestViewController alloc] initWithNibName:@“ TestView” bundle:nil]; [testView presentWithSuperview:self.navigationController.view]; 会正常工作,但是,如果您尝试释放或自动释放视图,则对该视图内方法的任何调用都会导致错误的访问异常
Mick Walker 2010年

你确定吗?我认为[superview addSubview:]将保留该视图,因此您应该可以释放它。
克里斯托弗·约翰逊

如果调用presentWithSuperview,则释放testView会崩溃。它还显示任何NavigationController工具栏等“下的”显示
瑞安布克

很长时间以来,这对我来说都很好,但是在横向模式下不再起作用。有人遇到同样的问题吗?
Jeffry van de Vuurst,2015年

19

苹果在iOS 8中批准的方法是将modalPresentationStyle设置为'UIModalPresentationOverCurrentContext'。

从UIViewController文档中:

UIModalPresentationOverCurrentContext

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

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

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

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/

WWDC 2014的“ iOS 8中的View Controller Advances”视频对此进行了详细介绍。

确保为您显示的视图控制器提供清晰的背景色(否则,它仍将显示为不透明)。


它在iOS8和iOS9上给了我黑屏
胡达

实际上,如果您将视图控制器的视图背景色设置为Alpha值低于1,则可以正常工作
Pierre

16

还有另一个选项:在显示模态控制器之前,请捕获整个窗口的屏幕截图。将捕获的图像插入UIImageView并将图像视图添加到要显示的控制器视图中。然后发送回去。在图像视图上方插入另一个视图(背景黑色,alpha 0.7)。显示您的模态控制器,它看起来是透明的。刚刚在运行iOS 4.3.1的iPhone 4上尝试过。喜欢魅力。


好人,我实现了这一点对我来说很棒。添加遵循此概念的代码。
伊舒岛2011年

没有人说这会很容易!:-)
Krumelur 2011年

您如何用这种方法支持设备旋转?
凯尔·克莱格

10

这已经很老了,但是我解决了如下相同的问题:由于我需要在iPhone中提供一个导航控制器,因此添加子视图并不是一个可行的解决方案。

所以我做了什么:

1)在呈现视图控制器之前,请为当前屏幕截图:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

2)创建要显示的视图控制器,并将背景添加为子视图,然后将其发送回。

UIViewController * presentingVC = [UIViewController new];
UIImageView * backgroundImageOfPreviousScreen = [[UIImageView alloc] initWithImage:backgroundImage];
[presentingVC.view addSubview:backgroundImageOfPreviousScreen];
[presentingVC.view sendSubviewToBack:backgroundImageOfPreviousScreen];

3)展示您的视图控制器,但在此之前,在新的视图控制器中,在viewDidLoad中添加一个透明视图(我使用过ILTranslucentView)

-(void)viewDidLoad
{
    [super viewDidLoad];
    ILTranslucentView * translucentView = [[ILTranslucentView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:translucentView];
    [self.view sendSubviewToBack:translucentView];
}

就这样!


太棒了 在半透明视图旁边,所有操作都很好,导致屏幕快照消失。
Michal Shatz 2014年

这是一个很好的解决方案!最好将弹出窗口的控制器代码与父视图控制器分开。
1kmonkies,2014年

对我来说,我工作了,但必须要有背景知识
WillAppear

5

我在另一个问题中写下了关于此问题的发现,但要点是,您现在必须调用modalPresentationStyle = UIModalPresentationCurrentContext拥有全屏显示的所有内容。大多数情况下,它是[UIApplication sharedApplication] .delegate.window的rootViewController。也可能是与一起提供的新UIViewController modalPresentationStyle = UIModalPresentationFullScreen

如果您想知道我是如何专门解决此问题的,请阅读我的其他更详细的文章。祝好运!


5

在IOS 8中,这似乎已损坏,我使用的是导航控制器,显示的上下文是“导航菜单”上下文,在我们的情况下是滑动菜单控制器。

我们正在使用pod'TWTSideMenuViewController','0.3'尚未检查这是否与库或上述方法有关。


5

这在iOS 8-9中对我有用:

1-用Alpha设置视图控制器的背景

2-添加以下代码:

TranslucentViewController *tvc = [[TranslucentViewController alloc] init];
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[tvc setModalPresentationStyle:UIModalPresentationOverCurrentContext];

[self.navigationController presentViewController:tvc animated:YES completion:nil];

4

我知道这是一个很老的问题。我被困在这个问题上,并且能够从这个话题中找到线索。所以把我如何得到它工作在这里:)。我正在使用情节提要,并且已选择要显示的ViewController。视图控制器具有透明的背景色。现在,在segue的“属性”检查器中,将演示文稿设置为“在当前上下文中”。我正在为iPhone开发。

segue的属性检查器


谢谢,也可以通过编程设置UIModalPresentationStyle.OverCurrentContext来工作
guoleii


3

在我的情况下,我在同一个viewController上有视图。因此,制作一个新的视图控制器来保存UIView。通过设置其alpha属性使该视图透明。然后在一个按钮上单击,我编写了此代码。看上去不错。

UIGraphicsBeginImageContext(objAppDelegate.window.frame.size);
    [objAppDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();



    UIViewController *controllerForBlackTransparentView=[[[UIViewController alloc] init] autorelease];
    [controllerForBlackTransparentView setView:viewForProfanity];

    UIImageView *imageForBackgroundView=[[UIImageView alloc] initWithFrame:CGRectMake(0, -20, 320, 480)];
    [imageForBackgroundView setImage:viewImage];

    [viewForProfanity insertSubview:imageForBackgroundView atIndex:0];

    [self.navigationController presentModalViewController:controllerForBlackTransparentView animated:YES];

它显示了我想要的。希望它能帮助一些人。


2

这是我创建的可解决问题的类别。

    //
    //  UIViewController+Alerts.h
    //

    #import <UIKit/UIKit.h>

    @interface UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated;
    - (void)dismissAlertViewControllerAnimated:(BOOL)animated;

    @end


    //
    //  UIViewController+Alerts.m
    //

    #import "UIViewController+Alerts.h"

    @implementation UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated
    {
            // Setup frame of alert view we're about to display to just off the bottom of the view
            [alertViewController.view setFrame:CGRectMake(0, self.view.frame.size.height, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];

            // Tag this view so we can find it again later to dismiss
            alertViewController.view.tag = 253;

            // Add new view to our view stack
            [self.view addSubview:alertViewController.view];

            // animate into position
            [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                    [alertViewController.view setFrame:CGRectMake(0, (self.view.frame.size.height - alertViewController.view.frame.size.height) / 2, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];
            }];      
    }

    - (void)dismissAlertViewControllerAnimated:(BOOL)animated
    {
            UIView *alertView = nil;

            // find our tagged view
            for (UIView *tempView in self.view.subviews)
            {
                    if (tempView.tag == 253)
                    {
                            alertView = tempView;
                            break;
                    }
            }

            if (alertView)
            {
                    // clear tag
                    alertView.tag = 0;

                    // animate out of position
                    [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                            [alertView setFrame:CGRectMake(0, self.view.frame.size.height, alertView.frame.size.width, alertView.frame.size.height)];
                    }];      
            }
    }

    @end

4
仅供参考,无需在dismiss方法中自行遍历子视图。该框架将通过[self.view viewWithTag:253]为您完成此任务;
SteveB 2012年

在此示例中,Dave Wood的类别按原样显示您的视图。因此,还必须将xib视图的Alpha设置的背景设置为小于1,以获得半透明效果。
罗勒·布尔克

当在可滚动视图(例如表格视图)上显示时,此类别存在问题:滚动有效。那很糟。用户可以在屏幕外滚动显示的视图。基础呈现视图的内容出现在屏幕上。
罗勒·布尔克

此后,我更新了此类别。您可以在此处获取代码:gist.github.com/4423365。我在表视图和集合视图上使用它,而没有您描述的滚动问题。
Dave Wood

2

经过大量研究后,看来这将解决我们的问题并达到我们的目的。

创建带有标识符的从源VC到目标VC的序列。

例如“ goToDestinationViewController”,让生活变得轻松,让我们考虑当前的视图控制器,即,您希望在透明视图后面的那个作为源,将目标作为目标

现在在源VC中的viewDidLoad:或view中

performSegueWithIdentifier("goToDestinationViewController", sender: nil)

好,我们已经完成了一半。现在转到您的故事板。单击segue。应该看起来像这样: segue

将选项更改为显示的内容。

现在是真正的解决方案。

在目标视图控制器的viewDidLoad中添加此代码。

self.modalPresentationStyle = .Custom

................................................... ..............那很容易............. ...................................................


1
self.modalPresentationStyle = .custom在Swift 3,Xcode 8中,设置对我有效果,以模态形式呈现具有透明背景的实际视图控制器。唯一的问题是,如果呈现的视图控制器嵌入在标签栏控制器中,则标签栏显示在透明面板的前面背景视图。
mtso

因此,如果正在使用标签栏,tabBarController.tabBar.isHidden则应将当前视图控制器的设置为true
mtso

1

另一种方法是使用“容器视图”。只需将alpha设置为1以下并嵌入即可。XCode 5,目标是iOS7。

无法显示图片,信誉不足)))

可从iOS6获得容器视图。


1

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

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

但是通过这种方式,您会松散“从底部滑动”动画。


这在iPhone上对我不起作用。下面的视图仍然消失。我相信modalPresentationStyle仅适用于iPad。
jessepinho

如果您愿意,我可以向您发送所产生效果的屏幕。也许您的实现有问题。
malex

啊...是因为我不知道视图控制器必须是全屏的。(请参阅T先生的评论。)
jessepinho,2013年

1

我找到了适用于iOS 7及更高版本的优雅,简单的解决方案!

对于iOS 8,Apple添加了UIModalPresentationOverCurrentContext,但是它不适用于iOS 7和更低版本,因此我无法在我的情况下使用它。

请创建类别并输入以下代码。

.h文件

typedef void(^DismissBlock)(void);

@interface UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion;

@end

.m文件

#import "UIViewController+Ext.h"

@implementation UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion
{
    controller.modalPresentationStyle = UIModalPresentationCustom;

    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    __block UIView *overlay = [[UIView alloc] initWithFrame:keyWindow.bounds];
    if (color == nil) {
        color = [UIColor blackColor];
    }
    overlay.backgroundColor = color;
    overlay.alpha = alpha;

    if (self.navigationController != nil) {
        [self.navigationController.view addSubview:overlay];
    }
    else if (self.tabBarController != nil) {
        [self.tabBarController.view addSubview:overlay];
    }
    else {
        [self.view addSubview:overlay];
    }

    self.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:controller
                       animated:true
                     completion:presentCompletion];

    DismissBlock dismissBlock = ^(void) {
        [self dismissViewControllerAnimated:YES completion:nil];
        [UIView animateWithDuration:0.25
                         animations:^{
                             overlay.alpha = 0;
                         } completion:^(BOOL finished) {
                             [overlay removeFromSuperview];
                         }];
    };
    return dismissBlock;
}

@end

注意:它也适用于navigationContoller,tabBarController。

用法示例:

       // Please, insure that your controller has clear background
       ViewController *controller = [ViewController instance];
        __block DismissBlock dismissBlock = [self presentController:controller
                                                withBackgroundColor:[UIColor blackColor]
                                                           andAlpha:0.5
                                                  presentCompletion:nil];
        // Supposed to be your controller's closing callback
        controller.dismissed = ^(void) {
            dismissBlock();
        };

好好享受!请留下一些反馈。


0

这是到目前为止我发现的最好,最干净的方法:

@protocol EditLoginDelegate <NSObject>

- (void)dissmissEditLogin;

@end

- (IBAction)showtTransparentView:(id)sender {

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"foo bar"
                                                         delegate:self
                                                cancelButtonTitle:@"cancel"
                                           destructiveButtonTitle:@"destructive"
                                                otherButtonTitles:@"ok", nil];

    [actionSheet showInView:self.view];

}

- (void)willPresentActionSheet:(UIActionSheet *)actionSheet{

    UIStoryboard *loginStoryboard     = [UIStoryboard storyboardWithName:@"Login" bundle:nil];
    self.editLoginViewController      = [loginStoryboard instantiateViewControllerWithIdentifier:@"EditLoginViewController"];

    self.editLoginViewController.delegate = self;

    [self.editLoginViewController viewWillAppear:NO];
    [actionSheet addSubview:self.editLoginViewController.view];
    [self.editLoginViewController viewDidAppear:NO];
}


0

我尝试使用多种方法来解决,但仍然失败,最终实现了以下代码。

Swift的决议:

// A.swift init method
modalPresentationStyle = .currentContext // or overCurrentContent
modalTransitionStyle = .crossDissolve // dissolve means overlay

然后在B视图控制器中:

// B.swift
let a = A()
self.present(a, animated: true, completion: nil)

您还必须使ViewController的视图的backgroundColor也透明。view.backgroundColor = UIColor.clear
Michael Henry
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.