iOS:具有透明背景的Modal ViewController

我试图以透明的背景模态地呈现视图控制器。 我的目标是让呈现和呈现的视图控制器的视图同时显示。 问题是,当呈现animation完成时,呈现视图控制器的视图消失。

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

我知道我可以添加视图作为子视图,但我想避免这个解决scheme出于某种原因。 我怎么解决它?

以下代码仅适用于iPad。

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

我会去添加一个子视图。

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

模态视图

如果我是你,我不会这样做。 我会添加一个子视图,并做到这一点。 这似乎让我更好的控制了事情。

编辑:

正如Paul Linsay所提到的那样,由于iOS 8只需要UIModalPresentationOverFullScreen来显示ViewController的modalPresentationStyle。 这也会覆盖navigationBar和tabBarbutton。

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

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

从UIViewController文档:

UIModalPresentationOverCurrentContext

内容仅显示在父视图控制器的内容上的演示样式。 演示完成后,呈现内容下的视图不会从视图层次结构中删除。 所以如果呈现的视图控制器没有用不透明的内容填充屏幕,则底层内容显示通过。

在popup窗口中呈现视图控制器时,仅当过渡样式为UIModalTransitionStyleCoverVertical时才支持此演示样式。 尝试使用不同的转换样式会触发exception。 但是,如果父视图控制器不在popup窗口中,则可以使用其他过渡样式(除了部分curl过渡)。

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

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

来自WWDC 2014的'View Controller Advancements in iOS 8'video详细介绍了这一点。

注意:

  • 一定要给你呈现的视图控制器一个清晰的背景颜色,以免它实际上是透明的!
  • 你必须呈现之前设置这个参数,即在viewDidLoad中设置这个参数不会有任何影响

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

见附图

此代码在iOS6和iOS7下的iPhone上正常工作:

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

在这种情况下,你错过了滑动animation。 要保留animation,您仍然可以使用下面的“非优雅”扩展名:

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

如果我们的presentsV位于UINavigationController或UITabbarController的内部,则需要使用该控制器作为呈现VC。

此外,在iOS7中,您可以实现应用UIViewControllerTransitioningDelegate协议的自定义转换animation。 当然,在这种情况下,你可以获得透明的背景

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

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

在这里输入图像说明

这是一个黑客的方式,但对我来说这个代码工作(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

这个类别为我工作(ios 7,8和9)

H文件

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

M文件

 @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 

我用XCode 7的Interface Builder挣扎了一下,把Presentation Style设置为@VenuGopalTewari。 在这个版本中,segue似乎没有Over Current ContextOver Full Screen演示模式。 因此,要使其工作,我将模式设置为Default

在这里输入图像说明在这里输入图像说明

另外,我将模态显示的视图控制器的演示模式设置为Over Full Screen

在这里输入图像说明

具有透明背景的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中设置背景色为黑色,并减less不透明度

另一种方法是使用“容器视图”。 只要使α低于1并embeddedseque。 XCode 5,目标iOS7。 在iPhone上testing

在这里输入图像说明

容器视图从iOS6可用。 链接到博客文章。

我创build了一个对象来处理我称之为“叠加模式”的表示,这意味着它保留了背景的视图,并允许您具有透明背景的模式。

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

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

如果您呈现的视图控制器具有不同的preferredStatusBarStyle ,将modalPresentationCapturesStatusBarAppearance属性设置为YES并强制更新状态栏外观很重要。

这个对象应该有一个@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]; }]; } } 

这是一个模仿默认模态animation的幻灯片从底部animation,但你可以做任何你想要的。

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

此解决scheme适用于iOS 7+

我在呈现的视图控制器的init方法中添加了这三行,并且像一个魅力:

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

编辑(在iOS 9.3上工作):

 self.modalPresentationStyle = UIModalPresentationOverFullScreen; 

根据文件:

** UIModalPresentationOverFullScreen呈现视图覆盖屏幕的视图呈现样式。 演示完成后,呈现内容下的视图不会从视图层次结构中删除。 所以如果呈现的视图控制器没有用不透明的内容填充屏幕,则底层内容显示通过。

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

回顾一下这里的所有好的答案和评论,并在移动到新的ViewController时仍然有一个animation,这是我做的:(支持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]; 

如果你这样做,你会失去你的modalTransitionStyleanimation。 为了解决这个问题,你可以很容易的添加到你的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; } 

一个非常简单的方法(例如使用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 }]; 

这将以模态方式在Storyboard呈现一个UIViewController ,但具有半透明的背景。

适用于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) } } 

如果您使用的是模态search,请确保将其设置为此图像(如果需要,可以closuresanimation) 在这里输入图像说明

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

 @interface UIViewController (MBOverCurrentContextModalPresenting) /// @warning Some method of viewControllerToPresent will called twice before iOS 8, eg 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 

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

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

我们需要正确设置我们的Modal。

图像链接的目标

  • 首先,我们需要将视图控制器的视图背景更改为清除颜色。 这只是意味着它应该是透明的。 默认情况下,该视图是白色的。

  • 其次,我们需要select导致Login屏幕的Segue,并在Attribute Inspector中将Presentation设置为Over Current Context。 此选项仅在启用“自动布局”和“大小类别”时可用。

图像链接的目标

将导航的modalPresentationStyle设置为UIModalPresentationCustom

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

这个答案使用swift的解决scheme如下。

 let vc = MyViewController() vc.view.backgroundColor = UIColor.clear // or whatever color. vc.modalPresentationStyle = .overCurrentContent present(vc, animated: true, completion: nil) 

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

  1. 添加视图控制器(V2),以您想要的方式设置UI
  • 添加一个UIView – 设置背景黑色和不透明度为0.5
  • 添加另一个UIView(2) – 这将作为你的popup窗口(请注意,UIView和UIView(2)不能具有相同的级别/层次结构。不要使imageview成为视图的子视图,否则视图的不透明度会影响UIView(2))
  1. 现在V2 Modally

  2. 点击继续。 在“属性”检查器中,将“演示文稿设置为全屏” 。 删除animation,如果你喜欢

故事板

  1. selectV2。 在“属性”检查器中,将“演示文稿设置为全屏” 。 检查定义上下文并提供上下文

故事板

  1. select您的V2的MainView(请查看图片)。 将backgroundColor设置为清除颜色

故事板

Interesting Posts