IOS:具有透明背景的模态ViewController

我正在尝试以一种模式呈现一个视图控制器,带有一个透明的背景。我的目标是让呈现和呈现视图控制器的视图同时显示。问题是,当呈现动画结束时,呈现视图控制器的视图消失。

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

我知道我可以将视图添加为子视图,但出于某种原因,我想避免这种解决方案。我怎么才能修好它?

179280 次浏览

以下代码仅适用于iPad.

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

我会添加一个子视图。

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

模态视图

如果我是你,我就不会这么做。我会添加一个子视图并执行此操作。它似乎能让我更好地控制事情。

编辑:

正如Paul Linsay所提到的,自IOS 8以来,所需要的只是UIModalPresentationOverFullScreen,用于所呈现的ViewController的ModalPresentationStyle.这也包括导航栏和标签栏按钮。

另一种方法是使用“容器视图”。只需使alpha低于1并嵌入Seque.Xcode 5,目标是iOS7。在iPhone上测试。

enter image description here

容器视图可从iOS6中获得。 链接来发布相关的博客文章。

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

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

在本例中,您错过了幻灯片动画。要保留动画,您仍然可以使用以下“非优雅”扩展:

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

如果我们的PresentingV位于UINavigationController或UITabbarController内部,您需要将该控制器作为PresentingVC进行操作。

此外,在iOS7中,您可以应用UIViewControllerTransitioningDelegate协议来实现自定义过渡动画。当然,在这种情况下,你可以得到透明的背景

@interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate>

首先,在演示之前,您必须将_ABC设置为_0

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

这是一种有点笨拙的方式,但对我来说,这段代码是可行的(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.

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

在这里重述所有好的答案和评论,并且在移动到新的ViewController时仍然有一个动画,这是我所做的:(支持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动画。为了解决这个问题,您可以轻松地将以下内容添加到您的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;
}

对于那些试图在IOS 8中实现这一功能的人来说,“苹果批准的”显示透明模式视图控制器的方法是将modalPresentationStyle关于目前的ED控制器设置为UIModalPresentationOverCurrentContext

这可以在代码中完成,也可以通过在故事板中设置不间断连续的属性来完成。

从UIViewController文档:

UiModalPresentationOverCurrentContext

一种表示样式,其中内容仅显示在 父视图控制器的内容。呈现的下面的视图 显示时,不会从视图层次结构中删除内容 完成。因此,如果呈现的视图控制器没有填满屏幕 对于不透明内容,底层内容会显示出来。

在弹出窗口中显示视图控制器

时,此显示 仅当转换样式为时,才支持样式 UiModalTransitionStyleCoverVertical.尝试使用不同的 转换样式会触发异常。但是,您可以使用其他 过渡样式(部分卷曲过渡除外)如果父对象 视图控制器不在弹出窗口中。

适用于IOS 8.0及更高版本。

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

2014年全球开发者大会(WWDC)的“ IOS 8中的视图控制器改进”视频详细介绍了这一点。

注意:

  • 一定要给你的视图控制器一个清晰的背景颜色,以免它实际上不是透明的!
  • 您必须设置此以前 Presenting IE在_ABC中设置此参数PresentedViewController的_0不会有任何影响

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

它只有一个简单的方法:

- (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并强制更新状态栏外观非常重要。

此对象应具有_为0的_ABC

您希望此对象符合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];
}];
}
}

这是一个从底部滑入的动画,模仿默认的模态动画,但你可以让它成为你想要的任何东西。

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

此解决方案适用于IOS 7+

如果使用模式不间断连续,请确保将其设置为此图像(如果需要,可以关闭动画)。enter image description here

在IOS 8.0及更高版本中,可以通过将属性情态呈现风格设置为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];

See Image Attached

创建一个不间断连续以有模式地呈现,并将该不间断连续的呈现属性设置为覆盖当前上下文 它将100%

工作

enter image description here

在IOS 7和IOS 8上测试的完整方法。

@interface UIViewController (MBOverCurrentContextModalPresenting)


/// @warning Some method of viewControllerToPresent will called twice before iOS 8, e.g. 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

登录屏幕是模态的,这意味着它位于前一个屏幕的顶部。到目前为止,我们已经模糊了背景,但它没有模糊任何东西。它只是一个灰色的背景。

我们需要适当地设置我们的模态。

图像链接目标

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

  • 其次,我们需要选择引导到登录屏幕的不间断连续,并在属性检查器中,将表示设置为“当前上下文”。此选项仅在启用“自动布局”和“尺寸等级”时可用。

图像链接目标

这个类别对我来说很有用(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

按照@Venugopaltewari的建议,我在使用Xcode7的界面构建器设置演示风格时遇到了一些困难。在此版本中,不间断连续似乎没有Over Current ContextOver Full Screen演示模式。因此,为了使其正常工作,我将模式设置为Default

带的

enter image description here enter image description here

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

enter image description here

执行此操作的非常简单的方法(例如,使用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,但是具有半透明背景。

我在当前视图控制器的init方法中添加了这三行代码,效果非常好:

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

编辑(在IOS 9.3上工作):

self.modalPresentationStyle = UIModalPresentationOverFullScreen;

根据文件:

UIModalPresentationOverFullScreen 一种视图显示样式,其中显示的视图覆盖屏幕。演示完成时,所显示内容下的视图不会从视图层次结构中删除。因此,如果呈现的视图控制器没有用不透明的内容填充屏幕,底层内容就会显示出来。

适用于IOS 8.0及更高版本。

具有透明背景的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中将背景颜色设置为黑色并降低不透明度

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

将导航的modalPresentationStyle设置为UIModalPresentationCustom

并将显示的视图控制器的背景颜色设置为透明颜色。

使用SWIFT的解决方案如下所示。

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

如果您正在使用故事板,则可以执行以下步骤:

  1. 添加一个视图控制器(V2),按照您想要的方式设置UI
  • 添加uiview-将背景设置为黑色,不透明度设置为0.5
  • 添加另一个uiview(2)-这将作为您的弹出窗口(请注意,uiview和uiview(2)必须具有相同的级别/层次结构。不要让ImageView成为View的子视图,否则UIView的不透明度会影响UIView(2))
  1. 模态地呈现V2

  2. 单击“不间断连续”。在“属性”检查器中,将“演示”设置为“全屏”。如果您愿意,可以删除动画

Storyboard

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

Storyboard

  1. 选择V2的主视图(请检查图像)。将BackgroundColor设置为清晰的颜色

Storyboard

当然,您应该设置UIModalPresentationCurrentContext,但设置ClearColor的位置也非常重要!你不能在ViewDidLoad函数中设置背景,在视图加载之前设置它,就像在根视图控制器中或在控制器的初始化函数中一样。

actionController.view.backgroundColor = [UIColor clearColor];
[self presentViewController:actionController animated:YES completion:nil];

- (instancetype)init {


self = [super initWithNibName:nil bundle:nil];


if(self) {
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self.view setBackgroundColor:[UIColor clearColor]];
}


return self;
}

SWIFT 4.2

guard let someVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "someVC") as? someVC else {
return
}
someVC.modalPresentationStyle = .overCurrentContext


present(someVC, animated: true, completion: nil)