Vista modal transparente en el controlador de navegación

Intento crear una Vista modal transparente en la parte superior de mi controlador de navegación. ¿Alguien sabe si esto es posible?

Una vista modal cubrirá la vista sobre la que se coloca y la barra de navegación de su controlador de navegación. Sin embargo, si usa el enfoque -presentModalViewController: animado: una vez que finaliza la animación, la vista que acaba de cubrir desaparecerá, lo que hace que la transparencia de su vista modal no tenga sentido. (Puede verificar esto implementando los métodos -viewWillDisappear: y -viewDidDisappear: en su controlador de vista raíz).

Puede agregar la vista modal directamente a la jerarquía de vista de la siguiente manera:

UIView *modalView = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; modalView.opaque = NO; modalView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f]; UILabel *label = [[[UILabel alloc] init] autorelease]; label.text = @"Modal View"; label.textColor = [UIColor whiteColor]; label.backgroundColor = [UIColor clearColor]; label.opaque = NO; [label sizeToFit]; [label setCenter:CGPointMake(modalView.frame.size.width / 2, modalView.frame.size.height / 2)]; [modalView addSubview:label]; [self.view addSubview:modalView]; 

Agregar el modalView como una subvista a la vista raíz como esta no cubrirá la barra de navegación, pero cubrirá toda la vista debajo de ella. Intenté jugar con el origen del marco utilizado para iniciar modalView, pero los valores negativos hacen que no se muestre. El mejor método que encontré para cubrir toda la pantalla además de la barra de estado es agregar el modalView como una subvista de la ventana en sí:

 TransparentModalViewAppDelegate *delegate = (TransparentModalViewAppDelegate *)[UIApplication sharedApplication].delegate; [delegate.window addSubview:modalView]; 

La forma más fácil es usar la propiedad modalPresentationStyle de navigationController (pero tendrá que hacer la animación por su cuenta):

 self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext; [self presentModalViewController:modalViewController animated:NO]; modalViewController.view.alpha = 0; [UIView animateWithDuration:0.5 animations:^{ modalViewController.view.alpha = 1; }]; 

Lo logro más fácilmente configurando un “OverlayViewController” que se encuentra sobre todas las otras subvistas de mi ventana o vista raíz. Configúrelo en su delegado de aplicación o controlador de vista raíz, y conviértalo en un singleton para que se pueda acceder desde cualquier lugar en su código o vea la jerarquía del controlador. A continuación, puede llamar a métodos para mostrar vistas modales, mostrar indicadores de actividad, etc., siempre que lo necesite, y potencialmente pueden cubrir cualquier barra de tabs o controladores de navegación.

Código de muestra para el controlador de vista raíz:

 - (void)viewDidLoad { OverlayViewController *o = [OverlayViewController sharedOverlayViewController]; [self.view addSubview:o.view]; } 

Código de muestra que puede usar para mostrar su vista modal:

 [[OverlayViewController sharedOverlayViewController] presentModalViewController:myModalViewController animated:YES]; 

En realidad, no he usado -presentModalViewController:animated: con mi OverlayViewController pero espero que esto funcione bien.

Ver también: ¿Cómo se ve tu singleton Objective-C?

Tuve el mismo problema y la solución es agregar la vista modal con addSubview: y animar el cambio en la jerarquía de vista con animateWithDuration de UIView: delay: options: animations: completion:

Agregué una propiedad y 2 métodos a una subclase de UIViewController (FRRViewController) que incluye otras funcionalidades. Publicaré todo el material en gitHub pronto, pero hasta entonces puedes ver el código relevante a continuación. Para obtener más información, puede consultar mi blog: Cómo mostrar un controlador de vista modal transparente .

 #pragma mark - Transparent Modal View -(void) presentTransparentModalViewController: (UIViewController *) aViewController animated: (BOOL) isAnimated withAlpha: (CGFloat) anAlpha{ self.transparentModalViewController = aViewController; UIView *view = aViewController.view; view.opaque = NO; view.alpha = anAlpha; [view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { UIView *each = obj; each.opaque = NO; each.alpha = anAlpha; }]; if (isAnimated) { //Animated CGRect mainrect = [[UIScreen mainScreen] bounds]; CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height); [self.view addSubview:view]; view.frame = newRect; [UIView animateWithDuration:0.8 animations:^{ view.frame = mainrect; } completion:^(BOOL finished) { //nop }]; }else{ view.frame = [[UIScreen mainScreen] bounds]; [self.view addSubview:view]; } } -(void) dismissTransparentModalViewControllerAnimated:(BOOL) animated{ if (animated) { CGRect mainrect = [[UIScreen mainScreen] bounds]; CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height); [UIView animateWithDuration:0.8 animations:^{ self.transparentModalViewController.view.frame = newRect; } completion:^(BOOL finished) { [self.transparentModalViewController.view removeFromSuperview]; self.transparentModalViewController = nil; }]; } } 

Esto es lo que hice para resolver el problema: buscar los detalles, pero este enfoque funcionó muy bien para mí:

  • Tome una captura de pantalla de la vista subyacente. https://devforums.apple.com/message/266836 – esto lleva a un método listo que devuelve un UIView para la pantalla actual.
  • Entregar la captura de pantalla a la vista modal (utilicé una propiedad)
  • Presente la vista modal
  • En el viewDidAppear del controlador de vista modal, configure la imagen como UIImageView en el índice 0. Ajuste la posición vertical de la imagen por la altura de la barra de estado.
  • En la vista modal, la vista del controlador desaparecerá, elimine la imagen nuevamente

El efecto es:

  • La vista se anima como lo hace cualquier vista modal: las partes semitransparentes de la vista modal se deslizan sobre la vista existente
  • Tan pronto como la animación se detiene, el fondo se establece en la captura de pantalla: esto hace que parezca como si la vista anterior aún estuviera debajo aunque no lo esté.
  • Tan pronto como se inicia la animación desaparecer de la vista modal, la imagen se elimina. Mientras tanto, el sistema operativo muestra la vista de navegación anterior, por lo que la vista modal se desliza de forma transparente y fuera de la vista como era de esperar.

Traté de animar en mi propia vista de superposición, pero no funcionó muy bien. Tengo un accidente sin indicación de lo que se ha estrellado. En lugar de perseguir esto, hice la vista bg y funciona muy bien.

Código en la vista modal: creo que puede averiguar el rest, es decir, establecer la propiedad modalView.bgImage …

 - (void)viewDidAppear:(BOOL)animated { // background // Get status bar frame dimensions CGRect statusBarRect = [[UIApplication sharedApplication] statusBarFrame]; UIImageView *imageView = [[UIImageView alloc] initWithImage:self.bgImage]; imageView.tag = 5; imageView.center = CGPointMake(imageView.center.x, imageView.center.y - statusBarRect.size.height); [self.view insertSubview:imageView atIndex:0]; } - (void)viewWillDisappear:(BOOL)animated { [[self.view viewWithTag:5] removeFromSuperview]; } 
 self.modalPresentationStyle = UIModalPresentationCurrentContext; [self presentModalViewController:newview animated:YES]; 

y asegúrese de configurar el fondo de la vista modal para que sea transparente,

self.view.background = …. alpha: 0.x;

si configura modalPresentationStyle para el controlador de vista modal para:

viewController.modalPresentationStyle = 17;

La vista en el fondo no se elimina. (TWTweetComposeViewController lo usa).

Sin embargo, no intenté aprobar la revisión de la App Store con este código

Esta publicación sobre cómo mostrar una vista “Cargando …” semitransparente puede dar algunos consejos sobre cómo proceder.

Sí, tienes que agregar la vista manualmente, y si quieres deslizarte desde la parte inferior o lo que sea que tengas que hacer la animación tú mismo también.

Escribí una clase para hacer esto, y un selector de fecha semi-modal utilizando esa clase como ejemplo.

Puede encontrar documentación en esta publicación de blog , el código está en github

He estado investigando este mismo tema la semana pasada. Intenté todas las diversas respuestas y ejemplos encontrados en Google y aquí en StackOverflow. Ninguno de ellos funcionó tan bien.

Siendo nuevo en la progtwigción de iOS, no tenía conocimiento de algo llamado UIActionSheet . Por lo tanto, si está tratando de lograr esto para mostrar una superposición modal de botones (como un modal preguntando a alguien cómo quiere compartir algo), simplemente use UIActionSheet .

Aquí hay una página web que muestra un ejemplo de cómo hacer esto .

Obtuve esta idea de https://gist.github.com/1279713

Preparar: En la vista modal xib (o escena usando storyboard), configuro el fondo de pantalla completa UIImageView (lo engancho con el archivo .h y le doy una propiedad “backgroundImageView”) con 0.3 alpha. Y configuré el color de fondo de la vista (UIView) como negro claro.

Idea: Luego, en “viewDidLoad” del controlador de vista modal, capturo la captura de pantalla del estado original y configuré esa imagen en el UIImageView de fondo. Establezca el punto Y inicial en -480 y déjelo deslizar al punto Y 0 con una duración de 0,4 segundos con la opción de animación EaseInOut. Cuando descartemos el controlador de vista, solo haga lo contrario.

Código para la clase de controlador de vista modal

.h archivo:

 @property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView; - (void) backgroundInitialize; - (void) backgroundAnimateIn; - (void) backgroundAnimateOut; 

archivo .m:

 - (void) backgroundInitialize{ UIGraphicsBeginImageContextWithOptions(((UIViewController *)delegate).view.window.frame.size, YES, 0.0); [((UIViewController *)delegate).view.window.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); backgroundImageView.image=screenshot; } - (void) backgroundAnimateIn{ CGRect backgroundImageViewRect = backgroundImageView.frame; CGRect backgroundImageViewRectTemp = backgroundImageViewRect; backgroundImageViewRectTemp.origin.y=-480; backgroundImageView.frame=backgroundImageViewRectTemp; [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{ backgroundImageView.frame=backgroundImageViewRect; } completion:^(BOOL finished) { }]; } - (void) backgroundAnimateOut{ CGRect backgroundImageViewRect = backgroundImageView.frame; backgroundImageViewRect.origin.y-=480; [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{ backgroundImageView.frame=backgroundImageViewRect; } completion:^(BOOL finished) { }]; } 

En viewDidLoad, simplemente llame a:

 [self backgroundInitialize]; [self backgroundAnimateIn]; 

En cualquier lugar descartamos el controlador de vista modal, llamamos:

 [self backgroundAnimateOut]; 

Tenga en cuenta que esto SIEMPRE animará la imagen de fondo. Por lo tanto, si este estilo de transición del controlador de vista modal (o el estilo de transición segue) no está configurado en “Cubierta vertical”, es posible que no necesite llamar a los métodos de animación.

Finalmente logré esto, para una interfaz de navegación o barra de tabs, combinando un controlador de vista de superposición (ver: respuesta de pix0r) que está oculto / no oculto antes de ocultar o mostrar un controlador de vista basado en esta muy buena publicación de blog .

Con respecto al controlador de vista, la sugerencia es hacer que su vista de fondo sea clearColor , luego la vista de superposición semitransparente es visible y las vistas que se agregan como subvistas en el controlador de vista están al frente y, lo que es más importante, opacas.

Creé la biblioteca de soruce abierta MZFormSheetController para presentar la hoja de formulario modal en UIWindow adicional. Puede usarlo para presentar el controlador de vista modal de transparencia, incluso ajustar el tamaño del controlador de vista presentado.

Para iOS 8+, puede usar el estilo de presentación UIModalPresentationOverCurrentContext para el controlador de vista presentado para lograr el comportamiento deseado.

 UIViewController *viewController = [[UIViewController alloc] init]; viewController.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.9f]; viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext; [self presentViewController:viewController animated:YES completion:nil]; 

Si también necesita soportar iOS 7, revise este hilo .

Puede lograr un efecto de vista modal transparente / semitransparente al superponer un botón transparente / semitransparente tanto en la vista como en la barra de navegación.

Puede acceder a la barra de navegación a través de la propiedad navigationBar del UINavigationController.

Descubrí que UIButton, a diferencia de UILabel, atrapará los eventos del mouse y, por lo tanto, dará el comportamiento modal correcto.

Acabo de encontrar una solución para eso. Simplemente cree un 1X1 de UIViewController y agréguelo a su controlador de vista padre. Y muestre el controlador de vista modal transparente en ese UIViewController.

en viewDidLoad;

self.dummyViewController = [[UIViewController alloc] init]; [self.dummyViewController.view setFrame: CGRectMake (0, 0, 1, 1)]; [self.view addSubView: self.dummyViewController.view];

cuando necesite abrir un control transparente de pantalla;

[self.dummyViewController presentModalViewController: yourTransparentModalViewController animated: true];

Si necesita una pantalla como la adjunta, el siguiente código puede ayudarlo. enter image description here

El código:

 MyViewController * myViewController = [[MyViewController alloc] initWithNibName:nibName bundle:nil]; UINavigationController * myNavigationController = [[UINavigationController alloc] initWithRootViewController: myViewController]; myNavigationController.modalPresentationStyle = UIModalPresentationPageSheet; [self presentModalViewController: myNavigationController animated:YES]; 

Si quiere decir que desea una superposición de pantalla, use el control ParentViewController.view, colocará la barra de navegación anterior.

MyCustomViewController* myOverlayView = [[MyCustomViewController alloc] init]; [self.parentViewController.view addSubview:myOverlayView];

Esto funcionó para mí:

 UIViewController *modalViewController = [[UIViewController alloc] init]; modalViewController.view.backgroundColor = [UIColor whiteColor] colorWithAlpha:0.5]; [self showDetailViewController:modalViewController sender:nil];