Agregue una vista UIV sobre todo, incluso la barra de navegación

181

Quiero mostrar, por encima de cualquier otra vista, incluso la barra de navegación, una especie de vista "emergente" que se ve así:

  • Fondo negro de pantalla completa con un 0.5 alfa para ver el otro UIViewControllerdebajo.
  • una UIViewventana en el medio con algo de información (un calendario si quieres saberlo todo).

Para hacer eso, he creado un UIViewController que contiene los dos UIViews(fondo y ventana), y estoy tratando de mostrarlo. He intentado una simple [mySuperVC addSubview:myPopUpVC.view], pero todavía tengo la barra de navegación de arriba.

Intenté presentarlo como modal, pero la parte UIViewControllerinferior desaparece y pierdo el efecto de transparencia.

Cualquier idea para hacer esto, estoy seguro de que es bastante simple ...

¡Gracias!

Nicolas Roy
fuente
Agregue una subvista en la ventana de su aplicación. Manejar cambios de orientación puede ser complicado: stackoverflow.com/questions/8774495/…
Amar

Respuestas:

197

Puede hacerlo agregando su vista directamente a keyWindow:

UIView *myView = /* <- Your custom view */;
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:myView];

ACTUALIZACIÓN - Para Swift 4.1 y superior

let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(myView)
ROM.
fuente
2
Gracias :) Lamentablemente, si está en modo horizontal, debe girar la vista. No estoy seguro de saber cómo hacerlo correctamente.
Nicolas Roy
Sí, solo estoy en modo horizontal y myView aparece con una rotación de 90 grados. Parece ser de lo que están hablando aquí: stackoverflow.com/questions/8774495/…
Nicolas Roy
El problema de orientación ocurre en dispositivos anteriores a iOS8, para los cuales, lamentablemente, esta solución no funciona.
thgc
@NicolasRoy Autolayout ayudará
Darmen Amanbayev
44
No cubre la barra de pestañas. ¿Alguna solución para eso?
Manisha
134

[self.navigationController.view addSubview:overlayView]; es lo que realmente quieres

dalef
fuente
55
Necesitas configurar el marco
Gabriel Goncalves
1
Muy buena solución, especialmente, cuando agrega una vista como "controlador de vista hijo"
Richard Topchii
2
Esto no funciona con la vista de un controlador de vista secundaria. Cambiar el nivel z de la barra de navegación (como sugiere Nam) también funciona con los controladores de vista secundarios.
Tapani
Parece una solución más elegante que agregar vista a la ventana Clave. Como esto asegura una vista adicional, se mueve a lo largo de la animación de la vista base. Porque si la vista se agrega en la ventana clave, no viene con animación y debe eliminarse por separado si desea descartar el controlador.
soan saini
no es una ventana emergente, pero es lo correcto para mi caso. Gracias))
Dilshod Zopirov
112

Aquí hay una solución simple y elegante que está funcionando para mí. Puede establecer la posición z de la barra de navegación debajo de la vista:

self.navigationController.navigationBar.layer.zPosition = -1;

Solo recuerde volver a establecerlo en 0 cuando haya terminado.

Nam
fuente
1
Esto funciona mucho mejor que agregar la vista de superposición como una subvista a la vista del controlador de navegación (que por cierto causa un bloqueo). Esta solución de posición z probablemente sea mucho más confiable y cause menos problemas en el futuro.
Tapani
Esto funciona muy bien cuando se trabaja con guiones gráficos. ¡Puedes agregar la vista dentro del guión gráfico!
Jos Koomen
Funciona muy bien para mí también. Sería genial mencionar que zPosition debe volver a establecerse en el valor 0 (solo menciona que debería volver a establecerse cuando haya terminado). Y tengo tabBar (desde TabBarController en mi pantalla también. Traté de establecer zPosition pero al volver al valor 0 tabBar aún no era visible. Entonces, para tabBar es mejor usar la propiedad isHidden.
Libor Zapletal
1
No trabajes con accesibilidad. Al desplazarse sobre la vista no se enfocará.
antonjn
¡¡Te quiero!! <3
chr0x
57

Versiones rápidas para la respuesta comprobada:

Swift 4:

let view = UIView()
view.frame = UIApplication.shared.keyWindow!.frame
UIApplication.shared.keyWindow!.addSubview(view)

Swift 3.1:

let view = UIView()
view.frame = UIApplication.sharedApplication().keyWindow!.frame 
UIApplication.sharedApplication().keyWindow!.addSubview(view)
Kevin ABRIOUX
fuente
66
¿Puedo hacer que esto cubra toda la vista actual (controlador de vista), pero dejar el nuevo controlador de vista que se muestra arriba?
Michał Ziobro
24

Agregue su vista como la subvista de NavigationController.

[self.navigationController.navigationBar addSubview: overlayView)]

También puede agregarlo sobre la ventana:

UIView *view = /* Your custom view */;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[window addSubview:view];

Espero que esto ayude.. :)

Rashad
fuente
Se acerca la vista, pero cuando agregar un botón no se puede activar el botón o establecer un texto de etiqueta personalizado en la vista general
Vineesh TP
Funciona bien para mí:let navigationBar = viewController.navigationController!.navigationBar navigationBar.addSubview(coverView)
Arthur Clemens
22

Gran solución de Dalef en Swift:

self.navigationController?.view.addSubview(view)
Allreadyhome
fuente
11

La respuesta de @ Nam funciona muy bien si solo desea mostrar su vista personalizada, pero si su vista personalizada necesita interacción del usuario, debe deshabilitar la interacción para elnavigationBar .

self.navigationController.navigationBar.layer.zPosition = -1
self.navigationController.navigationBar.isUserInteractionEnabled = false

Como dijo en la respuesta de Nam, no olvide revertir estos cambios:

self.navigationController.navigationBar.layer.zPosition = 0
self.navigationController.navigationBar.isUserInteractionEnabled = true


Puede hacer esto de una mejor manera con una extensión:

extension UINavigationBar {
    func toggle() {
        if self.layer.zPosition == -1 {
            self.layer.zPosition = 0
            self.isUserInteractionEnabled = true
        } else {
            self.layer.zPosition = -1
            self.isUserInteractionEnabled = false
        }
    }
}

Y simplemente utilízalo así:

self.navigationController.navigationBar.toggle()
Hemang
fuente
1
Solución perfecta.. !! Probé tantas cosas y pasé mucho tiempo ... ¡¡pero esto funciona bien ... !!
Disidente
8

Versión rápida de la respuesta de @Nicolas Bonnet:

    var popupWindow: UIWindow?

func showViewController(controller: UIViewController) {
    self.popupWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
    controller.view.frame = self.popupWindow!.bounds
    self.popupWindow!.rootViewController = controller
    self.popupWindow!.makeKeyAndVisible()
}

func viewControllerDidRemove() {
    self.popupWindow?.removeFromSuperview()
    self.popupWindow = nil
}

No olvide que la ventana debe ser una propiedad fuerte, porque la respuesta original conduce a una desasignación inmediata de la ventana.

Unidad iOS
fuente
6

Te recomiendo que crees una nueva UIWindow:

UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = viewController;
window.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
window.opaque = NO;
window.windowLevel = UIWindowLevelCFShareCircle;
window.backgroundColor = [UIColor clearColor];

[window makeKeyAndVisible];

Luego puede administrar su vista en otro UIViewController. Para eliminar las ventanas:

[window removeFromSuperview];
window = nil;

Espero que ayude!

Nicolas Bonnet
fuente
3
Gracias, pero creo que falta algo porque no aparece nada: /
Nicolas Roy
6

Hay más de una forma de hacerlo:

1- Agregue su UIViewen UIWindowlugar de agregarlo UIViewController. De esta manera estará por encima de todo.

   [[(AppDelegate *)[UIApplication sharedApplication].delegate window] addSubview:view];

2- Use una transición personalizada que mantendrá su UIViewController mostrando en la parte posterior con un 0.5 alfa

Para eso te recomiendo que mires esto: https://github.com/Citrrus/BlurryModalSegue

Dani A
fuente
4
[[UIApplication sharedApplication].windows.lastObject addSubview:myView];
jold
fuente
3

En Swift 4.2 y Xcode 10

var spinnerView: UIView? //This is your view

spinnerView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
//Based on your requirement change width and height like self.view.bounds.size.width
spinnerView?.backgroundColor = UIColor.black.withAlphaComponent(0.6)
//        self.view.addSubview(spinnerView)
let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(spinnerView!)

En objetivo C

UIView * spinnerView; // Esta es tu vista

self.spinnerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height)];  
//Based on your requirement change width and height like self.view.bounds.size.width
self.spinnerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
// [self.view addSubview:self.spinnerView];
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:self.spinnerView];

Esto solo puede funcionar en modo vertical u horizontal.

Un código simple más es:

yourViewName.layer.zPosition = 1//Change you view name
iOS
fuente
2

Tenga en cuenta que si desea agregar la vista en pantalla completa, use solo el código a continuación

Agregue estas extensiones de UIViewController

public extension UIViewController {
   internal func makeViewAsFullScreen() {
      var viewFrame:CGRect = self.view.frame
      if viewFrame.origin.y > 0 || viewFrame.origin.x > 0 {
        self.view.frame = UIScreen.main.bounds
      }
   }
}

Continuar como proceso normal de adición de subvista

Ahora úselo para agregar UIViewController viewDidAppear

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

     self.makeViewAsFullScreen()
}
Paresh Navadiya
fuente
1

Usaría una subclase de UIViewController que contiene una "Vista de contenedor" que integra sus otros controladores de vista. Luego podrá agregar el controlador de navegación dentro de la Vista de contenedor (utilizando la relación de inserción segue, por ejemplo).

Consulte Implementación de un controlador de vista de contenedor

dulgan
fuente
1
UIApplication.shared.keyWindow?.insertSubview(yourView, at: 1)

Este método funciona con xcode 9.4, iOS 11.4

Ahmed R.
fuente
0
[self.navigationController.navigationBar.layer setZPosition:-0.1];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(10, 20, 35, 35)];
[view setBackgroundColor:[UIColor redColor]];
[self.navigationController.view addSubview:view];
[self.navigationController.view bringSubviewToFront:view];
self.navigationController.view.clipsToBounds = NO;
[self.navigationController.navigationBar.layer setZPosition:0.0];

ingrese la descripción de la imagen aquí

Fadi Abuzant
fuente
0

Debe agregar una subvista a la primera ventana con el tipo UITextEffectsWindow. Al primero, porque los teclados personalizados agregan su UITextEffectsWindow, y si agrega una subvista, esto no funcionará correctamente. Además, no puede agregar una subvista a la última ventana porque el teclado, por ejemplo, también es una ventana y no puede presentar desde la ventana del teclado. Entonces, la mejor solución que encontré es agregar una subvista (o incluso un controlador de vista push) a la primera ventana con el tipo UITextEffectsWindow, esta ventana cubre la vista de accesorios, la barra de navegación, todo.

let myView = MyView()
myView.frame = UIScreen.main.bounds

guard let textEffectsWindow = NSClassFromString("UITextEffectsWindow") else { return }
let window = UIApplication.shared.windows.first { window in
    window.isKind(of: textEffectsWindow)
}
window?.rootViewController?.view.addSubview(myView)
Viktoria
fuente