Ajoutez avant tout un UIView, même la barre de navigation

181

Je souhaite afficher, au-dessus de toutes les autres vues, même la barre de navigation, une sorte de vue "pop-up" qui ressemble à ceci:

  • fond noir plein écran avec un alpha de 0,5 pour voir l'autre en UIViewControllerdessous.
  • une UIViewfenêtre au milieu avec quelques informations, (un calendrier si vous voulez tout savoir).

Pour ce faire, j'ai créé un UIViewController qui contient les deux UIViews(arrière-plan et fenêtre), et j'essaye de l'afficher. J'ai essayé un simple [mySuperVC addSubview:myPopUpVC.view], mais j'ai toujours la barre de navigation ci-dessus.

J'ai essayé de le présenter comme un modal, mais le UIViewControllerdessous disparaît et je perds mon effet de transparence.

N'importe quelle idée pour faire ça, je suis sûr que c'est assez simple ...

Merci!

Nicolas Roy
la source
Ajoutez une sous-vue sur la fenêtre de votre application. La gestion des changements d'orientation peut être délicate: stackoverflow.com/questions/8774495/…
Amar

Réponses:

197

Vous pouvez le faire en ajoutant votre vue directement à keyWindow:

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

MISE À JOUR - Pour Swift 4.1 et supérieur

let currentWindow: UIWindow? = UIApplication.shared.keyWindow
currentWindow?.addSubview(myView)
ROM.
la source
2
Merci :) Malheureusement, si vous êtes en mode paysage, vous devez faire pivoter la vue. Je ne suis pas sûr de savoir comment faire cela correctement.
Nicolas Roy
Oui, je suis uniquement en mode paysage et myView apparaît avec une rotation de 90 degrés. Semble être ce dont ils parlent ici: stackoverflow.com/questions/8774495/…
Nicolas Roy
Le problème d'orientation se produit sur les appareils pré-iOS8, pour lesquels cette solution ne fonctionne malheureusement pas.
thgc
@NicolasRoy Autolayout aidera
Darmen Amanbayev
4
il ne couvre pas la barre d'onglets. Une solution pour ça?
Manisha
134

[self.navigationController.view addSubview:overlayView]; c'est ce que tu veux vraiment

Dalef
la source
5
Vous devez définir le cadre
Gabriel Goncalves
1
Très bonne solution, surtout lorsque vous ajoutez une vue en tant que "contrôleur de vue enfant"
Richard Topchii
2
Cela ne fonctionne pas avec la vue d'un contrôleur de vue enfant. La modification du niveau z de la barre de navigation (comme le suggère Nam) fonctionne également avec les contrôleurs de vue enfants.
Tapani
Il semble être une solution plus élégante que d'ajouter une vue à la fenêtre Clé. Comme cela garantit une vue ajoutée, se déplace le long de l'animation de la vue de base. Parce que si la vue est ajoutée sur la fenêtre clé, elle ne vient pas avec l'animation et doit être supprimée séparément si vous souhaitez fermer le contrôleur.
soan saini le
ce n'est pas fini, mais c'est juste la bonne chose pour mon cas. Merci))
Dilshod Zopirov
112

Voici une solution simple et élégante qui fonctionne pour moi. Vous pouvez définir la position z de la barre de navigation sous la vue:

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

N'oubliez pas de le remettre à 0 lorsque vous avez terminé.

Nam
la source
1
Cela fonctionne beaucoup mieux que d'ajouter la vue superposée en tant que sous-vue à la vue du contrôleur de navigation (ce qui provoque d'ailleurs un plantage). Cette solution de position z est probablement beaucoup plus fiable et causera moins de problèmes à l'avenir.
Tapani
Cela fonctionne très bien lorsque vous travaillez avec des storyboards. Vous pouvez ajouter la vue à l'intérieur du storyboard!
Jos Koomen
Fonctionne très bien pour moi aussi. Ce serait bien de mentionner que zPosition devrait être remis à la valeur 0 (vous mentionnez simplement qu'il devrait être remis en place une fois terminé). Et j'ai tabBar (de TabBarController dans mon écran aussi. J'ai essayé de définir zPosition mais en revenant à la valeur 0, tabBar n'était pas encore visible. Donc, pour tabBar, il est préférable d'utiliser la propriété isHidden.
Libor Zapletal
1
Ne travaillez pas avec l'accessibilité. Le panoramique sur la vue ne la focalisera pas.
antonjn
Je t'aime!! <3
chr0x
57

Versions Swift pour la réponse vérifiée:

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
la source
6
Puis-je faire de cette couverture toute la vue actuelle (contrôleur de vue), mais laisser le nouveau contrôleur de vue apparaissant affiché au-dessus?
Michał Ziobro
24

Ajoutez votre vue en tant que sous-vue de NavigationController.

[self.navigationController.navigationBar addSubview: overlayView)]

Vous pouvez également l'ajouter sur la fenêtre:

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

J'espère que cela t'aides.. :)

Rashad
la source
La vue d'ensemble arrive mais, lorsque l'ajout d'un bouton ne peut pas obtenir l'action du bouton ou définir le texte d'étiquette personnalisé sur l'overView
Vineesh TP
Fonctionne bien pour moi:let navigationBar = viewController.navigationController!.navigationBar navigationBar.addSubview(coverView)
Arthur Clemens
22

Excellente solution Dalef dans Swift:

self.navigationController?.view.addSubview(view)
Déjà à la maison
la source
11

La réponse de @ Nam fonctionne très bien si vous souhaitez simplement afficher votre vue personnalisée, mais si votre vue personnalisée nécessite une interaction de l'utilisateur, vous devez désactiver l'interaction pour lenavigationBar .

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

Comme dit dans la réponse de Nam, n'oubliez pas d'inverser ces changements:

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


Vous pouvez le faire d'une meilleure manière avec une extension:

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

Et utilisez-le simplement comme ceci:

self.navigationController.navigationBar.toggle()
Hemang
la source
1
solution parfaite .. !! J'ai essayé tellement de choses et j'ai passé tellement de temps .. mais cela fonctionne bien .. !!
Dishant
8

Version Swift de la réponse 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
}

N'oubliez pas que la fenêtre doit être une propriété forte, car la réponse d'origine conduit à une désallocation immédiate de la fenêtre

Unité iOS
la source
6

Je vous recommande de créer une nouvelle 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];

Ensuite, vous pouvez gérer votre vue dans un autre UIViewController. Pour supprimer les fenêtres:

[window removeFromSuperview];
window = nil;

espérons que cela aidera!

Nicolas Bonnet
la source
3
Merci, mais je pense qu'il manque quelque chose car rien n'apparaît: /
Nicolas Roy
6

Il y a plus d'une façon de le faire:

1- Ajoutez votre UIViewsur UIWindowau lieu de l'ajouter UIViewController. De cette façon, ce sera au-dessus de tout.

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

2- Utilisez une transition personnalisée qui gardera votre UIViewController affiché à l'arrière avec un alpha de 0,5

Pour cela, je vous recommande de regarder ceci: https://github.com/Citrrus/BlurryModalSegue

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

Dans Swift 4.2 et 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!)

Dans l' objectif C

UIView * spinnerView; // Ceci est votre vue

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

Cela ne peut fonctionner qu'en mode Portrait OU Paysage.

Un autre code simple est:

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

Notez que si vous souhaitez ajouter une vue en plein écran, utilisez uniquement le code ci-dessous

Ajoutez ces extensions 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
      }
   }
}

Continuer comme processus d'ajout normal de sous-vue

À utiliser maintenant dans l'ajout de viewDidAppear de UIViewController

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

     self.makeViewAsFullScreen()
}
Paresh Navadiya
la source
1

J'utiliserais une sous-classe UIViewController contenant une "vue de conteneur" qui incorpore vos autres contrôleurs de vue. Vous pourrez ensuite ajouter le contrôleur de navigation à l'intérieur de la vue Conteneur (en utilisant le segment de relation d'intégration par exemple).

Voir Implémentation d'un contrôleur de vue de conteneur

Dulgan
la source
1
UIApplication.shared.keyWindow?.insertSubview(yourView, at: 1)

Cette méthode fonctionne avec xcode 9.4, iOS 11.4

Ahmed R.
la source
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];

entrez la description de l'image ici

Fadi Abuzant
la source
0

Vous devez ajouter une sous-vue à la première fenêtre avec le type UITextEffectsWindow. Pour le premier, parce que les claviers personnalisés ajoutent leur UITextEffectsWindow, et si vous y ajoutez une sous-vue, cela ne fonctionnera pas correctement. En outre, vous ne pouvez pas ajouter une sous-vue à la dernière fenêtre car le clavier, par exemple, est également une fenêtre et vous ne pouvez pas présenter à partir de la fenêtre du clavier. Donc, la meilleure solution que j'ai trouvée est d'ajouter une sous-vue (ou même un contrôleur de vue push) à la première fenêtre avec le type UITextEffectsWindow, cette fenêtre couvre la vue accessoire, la barre de navigation - tout.

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
la source