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 Context
或Over 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
你希望这个对象符合UIViewControllerAnimatedTransitioning
和UIViewControllerTransitioningDelegate
协议,并实现以下方法:
- (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];
如果你这样做,你会失去你的modalTransitionStyle
animation。 为了解决这个问题,你可以很容易的添加到你的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,则可以按照以下步骤操作:
- 添加视图控制器(V2),以您想要的方式设置UI
- 添加一个UIView – 设置背景黑色和不透明度为0.5
- 添加另一个UIView(2) – 这将作为你的popup窗口(请注意,UIView和UIView(2)不能具有相同的级别/层次结构。不要使imageview成为视图的子视图,否则视图的不透明度会影响UIView(2))
现在V2 Modally
点击继续。 在“属性”检查器中,将“演示文稿设置为全屏” 。 删除animation,如果你喜欢
- selectV2。 在“属性”检查器中,将“演示文稿设置为全屏” 。 检查定义上下文并提供上下文
- select您的V2的MainView(请查看图片)。 将backgroundColor设置为清除颜色