【问题标题】:How to use presentModalViewController to create a transparent view如何使用 presentModalViewController 创建透明视图
【发布时间】:2010-10-09 21:59:41
【问题描述】:

我正在显示一个模态视图

[self presentModalViewController:controller animated:YES];

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

是否有保持视图透明的方法?

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

【问题讨论】:

  • 这个问题现在已经很老了。在寻找答案时,请寻找适用于您使用的 iOS 版本的答案。
  • 这个stackoverflow.com/q/27598846/1603234让我微笑,现在轮到你了:)
  • 你可以使用viewcontroller.modalPresentationStyle = .FormSheet

标签: ios iphone uiviewcontroller


【解决方案1】:

在 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, 请参阅下面的 cmets。

【讨论】:

  • 嗨.. 我这边 +1,因为它在 iOS 4 和 iPad 上运行良好。但是它将如何在 iPhone 3.0 中工作。谢谢
  • 它不适合我(iOS 5.0),有人可以显示一些代码吗?
  • 这似乎不适用于 iPhone/iPod,仅适用于 iPad(请参阅答案中链接的文档)。 @simpleBob:也许这就是它不适合你的原因?
  • 仅供参考:我在这篇文章中问过同样的问题:stackoverflow.com/questions/14419395/…
  • 我在 iOS 8 上测试过,我必须使用 Over Current Context 作为演示样式。
【解决方案2】:

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

【讨论】:

  • 谢谢,这证实了我的怀疑。
  • 我已向 Apple 提交了有关此问题的错误报告。打开雷达:openradar.appspot.com/radar?id=1062402
  • 问题在于呈现的视图不能有自己的自动旋转设置。
【解决方案3】:

我需要什么才能让它工作:

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

【讨论】:

  • 它很简单,谢谢我只保留我的代码 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法和瞧
  • 您也可以只在呈现视图控制器上设置modalPresentationStyle(而不是在窗口的rootViewController上)。
  • 谢谢!!甚至在你这样做时也能工作,[self performSegueWithIdentifier:@"open" sender:self];
  • 您可以随时在模态框的 viewdidload 中手动为视图设置动画。
  • 注意,正如下面T先生所说,modalPresentationStyle必须在当前全屏的视图控制器上设置。
【解决方案4】:

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

// 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];可以正常工作,但是如果您尝试释放或自动释放视图,则对该视图中的任何方法的调用都将导致错误的访问异常
  • 你确定吗?我认为视图会被[superview addSubview:]保留,所以你应该可以释放它。
  • 如果你调用 presentWithSuperview 然后释放 testView 它会崩溃。它还显示“在”任何 NavigationController 工具栏等的“下方”。
  • 这对我来说已经很长时间了,但它不再在横向模式下工作。有人有同样的问题吗?
【解决方案5】:

Apple 批准的在 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 中的视图控制器改进”视频对此进行了详细介绍。

确保为您呈现的视图控制器提供清晰的背景颜色(否则,它仍然会显得不透明)。

【讨论】:

  • 它在 iOS8 和 iOS9 上给我一个黑屏
  • 实际上,如果您将视图控制器的视图设置为 alpha 值低于 1 的背景颜色,则它可以工作
【解决方案6】:

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

【讨论】:

  • 好一个,我实现了这对我来说很棒。添加我遵循这个概念的代码。
  • 没有人说这会很容易! :-)
  • 您将如何使用这种方法支持设备轮换?
【解决方案7】:

这已经很老了,但我解决了同样的问题,如下所示: 由于我需要在 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];
}

仅此而已!

【讨论】:

  • 太棒了。除了导致屏幕截图消失的半透明视图之外,一切都运行良好。
  • 这是一个很好的解决方案!最好将弹出窗口的控制器代码与父视图控制器分开。
  • 对我来说工作但设置背景必须在 viewWillAppear 中
【解决方案8】:

我在different question 中写下了我对此的发现,但要点是您必须在目前拥有全屏的任何设备上调用modalPresentationStyle = UIModalPresentationCurrentContext。大多数时候,它是 [UIApplication sharedApplication].delegate.window 的 rootViewController。它也可以是一个新的 UIViewController,它带有modalPresentationStyle = UIModalPresentationFullScreen

如果您想知道我是如何专门解决这个问题的,请阅读我的另一篇更详细的帖子。祝你好运!

【讨论】:

    【解决方案9】:

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

    我们正在使用 pod 'TWTsideMenuViewController', '0.3' 尚未检查这是否是库或上述方法的问题。

    【讨论】:

      【解决方案10】:

      这在 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];
      

      【讨论】:

        【解决方案11】:

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

        【讨论】:

        • 谢谢,也可以通过设置 UIModalPresentationStyle.OverCurrentContext 以编程方式工作
        【解决方案12】:

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

        【讨论】:

        • 你能解释一下如何使用它吗?因为当我尝试调用代码时,它会导致 SIGABRT。
        【解决方案13】:

        在我的情况下,我在同一个 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];
        

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

        【讨论】:

          【解决方案14】:

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

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

          【讨论】:

          • 仅供参考,无需在dismiss方法中自己循环遍历子视图。该框架将使用 [self.view viewWithTag:253]; 为您完成
          • 本示例中 Dave Wood 的类别按原样显示您的视图。因此,您还必须将您的 xib 视图的 Alpha 设置的背景设置为低于 1 以获得半透明效果。
          • 此类别在呈现在可滚动视图(例如表格视图)上时存在问题:滚动有效。那很糟。用户可以在屏幕外滚动呈现的视图。底层呈现视图的内容出现在屏幕上。
          • 我已经更新了这个类别。您可以在此处获取代码:gist.github.com/4423365。我在表格视图和集合视图上使用它,没有您描述的滚动问题。
          【解决方案15】:

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

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

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

          现在在 viewDidLoad: 或视图中的源 VC 中

          performSegueWithIdentifier("goToDestinationViewController", sender: nil)
          

          很好,我们已经完成了一半。 现在去你的故事板。点击转场。应该是这样的: segue

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

          现在真正的解决方案来了。

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

          self.modalPresentationStyle = .Custom
          

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

          【讨论】:

          • 设置 self.modalPresentationStyle = .custom 在 Swift 3、Xcode 8 中以模态方式呈现具有透明背景的实际视图控制器对我有用。唯一的问题是,如果呈现视图控制器嵌入在选项卡栏控制器中,标签栏显示在透明背景视图的前面。
          • 所以——如果一个标签栏正在使用——那么呈现视图控制器的tabBarController.tabBar.isHidden应该被设置为true
          【解决方案16】:

          另一种方法是使用“容器视图”。只需使 alpha 低于 1 并嵌入序列。 XCode 5,面向 iOS7。

          无法显示图片,没有足够的声誉)))

          iOS6 中可用的容器视图。

          【讨论】:

            【解决方案17】:

            此代码在 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。
            • 如果你愿意,我可以给你发送最终效果的屏幕。你的实现可能有问题。
            • 啊...这是因为我不知道视图控制器必须是全屏的。 (参见 T 先生的评论。)
            【解决方案18】:

            我为 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();
                    };
            

            尽情享受吧!请留下一些反馈。

            【讨论】:

              【解决方案19】:

              这是迄今为止我发现的最好和最干净的方法:

              @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];
              }
              

              【讨论】:

                【解决方案20】:

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

                【讨论】:

                  【解决方案21】:

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

                  斯威夫特的解决方案:

                  // 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 的 view 的 backgroundColor 也是透明的。 view.backgroundColor = UIColor.clear
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-12-19
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-15
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多