iOS: Modal ViewController con background transparente

Estoy tratando de presentar un controller de vista de manera modal, con un background transparente. Mi objective es permitir que se muestren tanto la vista de los presentadores como la de los presentadores de visualización al mismo time. El problema es que, cuando finaliza la animation de presentación, desaparece la vista del controller de vista de presentación.

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

Sé que podría agregar la vista como una subvista, pero me gustaría evitar esta solución por alguna razón. ¿Cómo podría solucionarlo?

Este siguiente código solo funciona en el iPad.

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

Me gustaría agregar una vista secundaria.

Aquí hay una muy buena discusión. Mire los comentarios específicamente. No solo la respuesta.

Vista modal

Si fuera tú no lo haría. Yo agregaría una vista secundaria y lo haría. Parece que me da un mejor control sobre las cosas.

EDITAR:

Como lo menciona Paul Linsay, desde iOS 8 todo lo que se necesita es UIModalPresentationOverFullScreen para el modalPresentationStyle del ViewController que se presenta. Esto también cubriría los botones navigationBar y tabBar.

Para aquellos que intentan que esto funcione en iOS 8, la manera "aprobada por Apple" para mostrar un controller de vista modal transparente es mediante el establecimiento de modalPresentationStyle en el controller actual de ed a UIModalPresentationOverCurrentContext .

Esto se puede hacer en código, o configurando las properties de la segue en el guión gráfico.

De la documentation de UIViewController:

UIModalPresentationOverCurrentContext

Un estilo de presentación donde el contenido se muestra solo sobre el contenido del controller de vista principal. Las vistas debajo del contenido presentado no se eliminan de la jerarquía de vista cuando finaliza la presentación. Entonces, si el controller de vista presentado no llena la pantalla con contenido opaco, el contenido subyacente se muestra.

Cuando se presenta un controller de vista en un popover, este estilo de presentación solo es compatible si el estilo de transición es UIModalTransitionStyleCoverVertical. Intentar utilizar un estilo de transición diferente desencadena una exception. Sin embargo, puede usar otros styles de transición (excepto la transición de curvatura parcial) si el controller de vista principal no está en un popover.

Disponible en iOS 8.0 y versiones posteriores.

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

El video 'Ver avances de controller en iOS 8' de WWDC 2014 entra en esto con cierto detalle.

Nota:

  • Asegúrese de dar a su controller de vista presentado un color de background claro, ¡para que no sea realmente transparente!
  • viewDidLoad establecer esto antes de presentarse, es decir, configurar este parámetro en la viewDidLoad del presentedViewController no tendrá ningún efecto

En iOS 8.0 y superior se puede hacer configurando la propiedad modalPresentationStyle a 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]; 

Ver imagen adjunta

Este código funciona bien en iPhone bajo iOS6 y iOS7:

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

En este caso, se pierde la animation deslizante. Para conservar la animation, aún puede usar la siguiente extensión "no elegante":

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

Si nuestro V presentador se encuentra dentro del UINavigationController o UITabbarController, debe operar con esos controlleres como presentando VC.

Además, en iOS7 puedes implementar animation de transición personalizada aplicando el protocolo UIViewControllerTransitioningDelegate . Por supuesto, en este caso puedes get un background transparente

 @interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate> 

Primero, antes de presentar, debe establecer modalPresentationStyle

 modalViewController.modalPresentationStyle = UIModalPresentationCustom; 

Entonces tienes que implementar dos methods de protocolo

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

Lo último es definir tu transición personalizada en la class 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 } } 

Cree una segue para presentar modally y establezca la propiedad de presentación de esa segue en un context más extenso que funcionará 100%

introduzca la descripción de la imagen aquí

Es un poco hacky, pero para mí este código funciona (iOS 6):

 AppDelegate *appDelegate = (AppDelegate *)[[UIApplication shanetworkingApplication] 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; }]; }]; 

Este código también funciona en iPhone

Esta categoría funcionó para mí (ios 7, 8 y 9)

Archivo H

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

Archivo 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 

Luché un poco con el Interface Builder de XCode 7 para configurar el estilo de presentación como sugirió @VenuGopalTewari. En esta versión, parece que no hay un modo de presentación Over Current Context o Over Full Screen para la segue. Por lo tanto, para que funcione, establezco el modo en Default :

introduzca la descripción de la imagen aquí con introduzca la descripción de la imagen aquí

Además, establezco el modo de presentación del controller de vista presentado de manera modesta en la Over Full Screen :

introduzca la descripción de la imagen aquí

PresentViewController con background Transparente – en iOS 8 e 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]; 

Y en MYViewController configuramos el color de background negro y networkingucimos la opacidad

Alternativamente, se usa una "vista de contenedor". Simplemente haga alfa debajo de 1 e incruste con seque. XCode 5, objective iOS7. Probado en iPhone.

introduzca la descripción de la imagen aquí

Vista de contenedor disponible desde iOS6. Enlace a la publicación de blog sobre eso.

He creado un object para manejar la presentación de lo que yo llamo un "modal superpuesto", lo que significa que conserva la vista de background y le permite tener un modal con un background transparente.

Tiene un método único y simple que hace esto:

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

Es importante establecer la propiedad modalPresentationCapturesStatusBarAppearance en YES y obligar a que se actualice la apariencia de la barra de estado, si su controller de vista presentado tiene un modalPresentationCapturesStatusBarAppearance diferente.

Este object debe tener una @property (assign, nonatommic) isPresenting

Desea que este object cumpla con los protocolos UIViewControllerAnimatedTransitioning y UIViewControllerTransitioningDelegate e implementar los siguientes methods:

 - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { self.isPresenting = YES; return self; } - (id)animationControllerForDismissedController:(UIViewController *)dismissed { self.isPresenting = NO; return self; } 

y:

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

Esto hace una animation de diapositiva en la parte inferior que imita la animation modal pnetworkingeterminada, pero puedes hacer lo que quieras.

Lo importante es que la vista del controller de vista de presentación se quede en la parte posterior, lo que le permite crear un efecto transparente.

Esta solución funciona para iOS 7+

Agregué estas tres líneas en el método init en el controller de vista presentado y funciona como un encanto:

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

EDIT (trabajando en iOS 9.3):

 self.modalPresentationStyle = UIModalPresentationOverFullScreen; 

Según la documentation:

** UIModalPresentationOverFullScreen Un estilo de presentación de vista en el que la vista presentada cubre la pantalla. Las vistas debajo del contenido presentado no se eliminan de la jerarquía de vista cuando finaliza la presentación. Entonces, si el controller de vista presentado no llena la pantalla con contenido opaco, el contenido subyacente se muestra.

Disponible en iOS 8.0 y posterior. **

Para recapitular todas las buenas respuestas y comentarios aquí y todavía tener una animation mientras se mueve a su nuevo ViewController esto es lo que hice: (Compatible con iOS 6 y versiones posteriores)

Si está utilizando un UINavigationController \ UITabBarController este es el path a seguir:

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

Si lo haces, perderás la animation modalTransitionStyle . Para resolverlo, puede agregar fácilmente a su class SomeViewController esto:

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

Una forma muy simple de hacerlo (usar Storyboards , por ejemplo) es:

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

Esto presentará un UIViewController en un Storyboard modal, pero con un trasbackground translúcido.

Trabajando para 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) } } 

Si está utilizando segue modal, asegúrese de configurarlo como esta image (puede desactivar la animation si lo desea) introduzca la descripción de la imagen aquí

Un método completo probado en iOS 7 y iOS 8.

 @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 

en appdelegate:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[_window rootViewController]setModalPresentationStyle:UIModalPresentationCurrentContext]; return YES; } 

en la primera vista del controller desde donde tiene que cargar la siguiente vista:

  NextViewController *customvc = [[NextViewController alloc]init]; [self presentViewController:customvc animated:YES completion:^{ }]; 

en su nextViewController que se debe agregar transparente:

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

La pantalla de inicio de session es modal, lo que significa que se encuentra en la parte superior de la pantalla anterior. Hasta ahora tenemos background borroso, pero no está borrando nada; Es solo un background gris.

Tenemos que establecer nuestro Modal correctamente.

objective de enlace de image

  • En primer lugar, necesitamos cambiar el background de Ver vista del controller a Color claro. Simplemente significa que debe ser transparente. De forma pnetworkingeterminada, esa vista es blanca.

  • En segundo lugar, debemos seleccionar el Segue que conduce a la pantalla de inicio de session, y en el inspector de attributes, establecer la presentación en el context más reciente. Esta opción solo está disponible con Auto Layout y Clases de tamaño habilitadas.

objective de enlace de image

Establezca modalPresentationStyle de modalPresentationStyle de navigation en modalPresentationStyle UIModalPresentationCustom

y configure el color de background del controller de vista presentado como color claro.

La solución a esta respuesta usando swift sería la siguiente.

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

Si está utilizando Storyboard, puede seguir este paso:

  1. Agregue un controller de vista (V2), configure la interfaz de usuario de la forma que desee
  • agregue una UIView: establezca el background en negro y la opacidad en 0.5
  • agregue otra UIView (2), que servirá como su window emergente (por favor, tome nota de que UIView y UIView (2) no deben tener el mismo nivel / jerarquía. No convierta a imageview en hijo de la vista de lo contrario la opacidad de uiview afectará la UIView (2))
  1. Presente V2 Modalmente

  2. Haz clic en segue. En el inspector de Atributos, Establecer presentación como en pantalla completa . Eliminar animation si te gusta

Guión gráfico

  1. Seleccione V2. En el inspector de Atributos, Establecer presentación como en pantalla completa . Check define el context y proporciona un context

Guión gráfico

  1. Seleccione la vista principal de su V2 (por favor verifique la image). Establecer color de background a color claro

Guión gráfico