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!


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)

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


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é.


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)

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.. :)


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


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()

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


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!


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


4
[[UIApplication sharedApplication].windows.lastObject addSubview:myView];

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

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

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


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

Cette méthode fonctionne avec xcode 9.4, iOS 11.4


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


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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.