如何使用presentModalViewController创建透明视图

时间:2009-02-25 20:20:42

标签: ios iphone uiviewcontroller

我正在用

显示模态视图
[self presentModalViewController:controller animated:YES];

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

是否保持视图透明?

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

21 个答案:

答案 0 :(得分:85)

在iOS 3.2之后,有一种方法可以做到这一点而不需要任何“技巧” - see the documentation for the modalPresentationStyle property。你有一个rootViewController,它将呈现viewController。 所以这是成功的代码:

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

使用此方法,viewController的背景将是透明的,底层的rootViewController将是可见的。 请注意,这似乎只适用于iPad,请参阅下面的评论。

答案 1 :(得分:62)

您的视图仍然是透明的,但是一旦您的模态控制器位于堆栈的顶部,它背后的视图就会被隐藏(就像任何最顶层的视图控制器一样)。解决方案是自己手动设置视图动画;那么后面的viewController将不会被隐藏(因为你不会'离开'它)。

答案 2 :(得分:48)

我需要让它工作:

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

答案 3 :(得分: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];    
}

答案 4 :(得分:19)

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

来自UIViewController文档:

  

<强> UIModalPresentationOverCurrentContext

     

仅在内容上显示内容的演示样式   父视图控制器的内容。提出的观点   在演示文稿时,不会从视图层次结构中删除内容   饰面。因此,如果呈现的视图控制器没有填满屏幕   对于不透明的内容,基础内容会显示出来。

     

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

     

适用于iOS 8.0及更高版本。

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

来自WWDC 2014的“在iOS 8中查看控制器进展”视频详细介绍了这一点。

请务必为您呈现的视图控制器提供清晰的背景色(否则,它仍会显示为不透明)。

答案 5 :(得分:16)

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

答案 6 :(得分: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];
}

就是这样!

答案 7 :(得分: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];

答案 8 :(得分:5)

这似乎在IOS 8中被破坏,我正在使用导航控制器,正在显示的上下文是导航菜单上下文,在我们的示例中是滑动菜单控制器。

我们正在使用pod&#39; TWTSideMenuViewController&#39;,&#39; 0.3&#39;尚未检查这是否是库的问题或上述方法。

答案 9 :(得分:4)

我在different question中写下了我对此的调查结果,但其中的要点是,你必须在全屏幕上调用modalPresentationStyle = UIModalPresentationCurrentContext。大多数情况下,它是[UIApplication sharedApplication] .delegate.window的rootViewController。它也可能是一个带有modalPresentationStyle = UIModalPresentationFullScreen的新UIViewController。

如果您想知道我是如何具体解决这个问题的,请阅读我的其他更详细的帖子。祝你好运!

答案 10 :(得分:4)

我知道这是一个非常古老的问题。我被困在这个问题上,我能够从这个线程中获得领先优势。所以放在这里我是如何工作的:)。 我正在使用故事板,我已经看到要呈现的ViewController。视图控制器具有透明背景颜色。现在在segue的Attributes检查器中,我将演示文稿设置为&#34; Over current context&#34;。它对我有用。我正在为iPhone开发。

Attributes Inspector of the segue

答案 11 :(得分: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];

它显示了我想要的东西。希望对某人有所帮助。

答案 12 :(得分:3)

我已经创建了open soruce库MZFormSheetController来在其他UIWindow上呈现模态表单。您可以使用它来呈现透明模式视图控制器,甚至可以调整呈现的视图控制器的大小。

答案 13 :(得分: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

答案 14 :(得分: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();
        };

享受吧!请保留一些反馈意见。

答案 15 :(得分:1)

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

使用标识符从源VC创建segue到目标VC。

例如“goToDestinationViewController” 好吧让生活变得轻松让我们考虑当前的视图控制器,即你想要透明视图作为源和目标作为目标的那个

现在在viewDidLoad:或

中的源VC中
performSegueWithIdentifier("goToDestinationViewController", sender: nil)
好的,我们已经完成了一半。 现在转到你的故事板。点击segue。它应该是这样的: segue

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

现在是真正的解决方案。

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

self.modalPresentationStyle = .Custom

............................................... ..........................这很容易...................... ............................................

答案 16 :(得分:1)

此代码适用于iOS6和iOS7下的iPhone:

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

但是通过这种方式你可以放松“从底部滑动”动画。

答案 17 :(得分:1)

替代方法是使用“容器视图”。只需将alpha设置为低于1并嵌入seque。 XCode 5,目标是iOS7。

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

iOS6提供的容器视图。

答案 18 :(得分:0)

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

斯威夫特的决议:

// 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)

答案 19 :(得分:0)

我遇到的最佳解决方案是使用addChildViewController方法。 这是一个很好的例子:Add a child view controller's view to a subview of the parent view controller

答案 20 :(得分: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];
}