iPhone masquer la barre de navigation uniquement sur la première page

383

J'ai le code ci-dessous qui cache et montre la barre de navigation. Il est masqué lors du chargement de la première vue, puis masqué lorsque les «enfants» sont appelés. Le problème est que je ne trouve pas l'événement / l'action pour le déclencher pour qu'il se cache à nouveau lorsqu'ils reviennent à la vue racine ....

J'ai un bouton "test" sur la page racine qui fait manuellement l'action mais ce n'est pas joli et je veux que ce soit automatique.

-(void)hideBar 
{
    self.navController.navigationBarHidden = YES;
}
-(void)showBar 
{       
    self.navController.navigationBarHidden = NO;
}
Lee Armstrong
la source

Réponses:

1036

La meilleure solution que j'ai trouvée est de faire ce qui suit dans le premier contrôleur de vue .

Objectif c

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:NO animated:animated];
    [super viewWillDisappear:animated];
}

Rapide

override func viewWillAppear(animated: Bool) {
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
    super.viewWillAppear(animated)
}

override func viewWillDisappear(animated: Bool) {
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
    super.viewWillDisappear(animated)
} 

Cela entraînera l'animation de la barre de navigation depuis la gauche (avec la vue suivante) lorsque vous poussez la suivante UIViewControllersur la pile, et l'animation vers la gauche (avec l'ancienne vue), lorsque vous appuyez sur le bouton de retour sur la UINavigationBar.

Veuillez noter également que ce ne sont pas des méthodes déléguées, vous remplacez UIViewControllerl'implémentation de ces méthodes, et selon la documentation, vous devez appeler l'implémentation du super quelque part dans votre implémentation .

Alan Rogers
la source
2
C'est vraiment génial! J'avais du mal avec ça depuis au moins une journée. Merci!!!
James Testa
26
AVERTISSEMENT: cela crée un très mauvais bogue lors d'un balayage rapide. Supposons que A (pas de barre de navigation) et B (avec barre de navigation) poussés sur la pile. Lorsque vous êtes en vue B et que vous effectuez un balayage arrière rapide, mais relâchez suffisamment tôt pour rester sur B, la barre de navigation est toujours masquée. Maintenant, il n'y a plus moyen de revenir en arrière. Cela est dû à animated=YES. Je sais que cela semble laid animated=NO, mais il semble que lorsque l'animation pour masquer la barre de navigation n'est pas encore terminée, l'animation pour la montrer à nouveau est ignorée. Pas encore de solution.
fabb
3
Dans Swift: remplacer func viewWillAppear (animated: Bool) {self.navigationController? .SetNavigationBarHidden (true, animated: true) super.viewWillAppear (true)} override func viewWillDisappear (animated: Bool) {self.navigationController? .SetNavigationBarHidden animé: false) super.viewWillDisappear (true)}
Kitson
7
La question a été répondue en 2010 et m'aide fin 2015! Je vous remercie.
oyalhi
1
Voilà ce que j'appelle une réponse légendaire. Superbe compagnon de truc. Même après des décennies de travail ... Mis en œuvre la même chose rapidement, fonctionnant parfaitement. +1 pour votre réponse @Alan Rogers
onCompletion
62

Une autre approche que j'ai trouvée consiste à définir un délégué pour NavigationController:

navigationController.delegate = self;

et utiliser setNavigationBarHiddendansnavigationController:willShowViewController:animated:

- (void)navigationController:(UINavigationController *)navigationController 
      willShowViewController:(UIViewController *)viewController 
                    animated:(BOOL)animated 
{   
    // Hide the nav bar if going home.
    BOOL hide = viewController != homeViewController;
    [navigationController setNavigationBarHidden:hide animated:animated];
}

Un moyen facile de personnaliser le comportement de chacun ViewControlleren un seul endroit.

Chad M.
la source
Quand cela sera-t-il appelé?
Zalak Patel
1
Solution parfaite. Ce devrait être la réponse acceptée. Merci!
Samah
Réponse parfaite. Cela fonctionne également si nous ne pouvons pas remplacer les méthodes viewWillAppear et viewWillDisappear sur le premier contrôleur de vue.
pjuzeliunas
1
Impressionnant. La réponse choisie fonctionne bien, mais uniquement dans les applications simples. Cette réponse fonctionne lorsque la barre de navigation se trouve dans un contrôleur d'onglets et pousse / présente divers VC de différentes manières.
Jonathan Winger-Lang
C'est la meilleure réponse. La première réponse peut se produire un bogue comme la description de @ fabb .
Ryan.Yuen
19

Un léger ajustement que j'ai dû apporter aux autres réponses consiste à afficher la barre dans viewWillDisappear uniquement si la raison de sa disparition est due à un élément de navigation poussé dessus. En effet, la vue peut disparaître pour d'autres raisons.

Je ne dévoile donc la barre que si cette vue n'est plus la plus haute:

- (void) viewWillDisappear:(BOOL)animated
{
    if (self.navigationController.topViewController != self)
    {
        [self.navigationController setNavigationBarHidden:NO animated:animated];
    }

    [super viewWillDisappear:animated];
}

la source
3
+1, vous ne voulez généralement pas afficher la barre de navigation lorsque vous appuyez sur une boîte de dialogue modale.
João Portela
18

Je mettrais le code dans le délégué viewWillAppear sur chaque vue affichée:

Comme ça où vous devez le cacher:

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject hideBar];
}

Comme ça où vous devez le montrer:

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject showBar];
}
Pablo Santa Cruz
la source
Lee, si cela a résolu votre problème, marquez Pablo comme la réponse «solution».
Rog
2
Le seul problème avec cela est que la barre de navigation "apparaît" et apparaît dans la vue lorsque vous naviguez d'une vue à la suivante. Est-il possible que la barre de navigation ne soit pas là sur la première vue, et lorsque la deuxième vue glisse en place, elle a la barre de navigation, sans éclater?
Henning
2
@henning Pour faire glisser / sortir la barre de navigation comme vous vous y attendez, vous devez utiliser setNavigationBarHidden: animated :. Voir la réponse d'Alan Rogers ci-dessous (qui devrait vraiment être marquée comme la «solution»).
Nick Forge
2
Cette réponse est légèrement fausse (viewWill / DidAppear) devrait appeler super. Voir également ma réponse ci-dessous pour une solution où vous n'avez pas besoin de l'ajouter à CHAQUE contrôleur de vue.
Alan Rogers
15

La réponse actuellement acceptée ne correspond pas au comportement souhaité décrit dans la question. La question demande que la barre de navigation soit masquée sur le contrôleur de vue racine, mais visible partout ailleurs, mais la réponse acceptée masque la barre de navigation sur un contrôleur de vue particulier. Que se passe-t-il lorsqu'une autre instance du premier contrôleur de vue est poussée sur la pile? Il masquera la barre de navigation même si nous ne regardons pas le contrôleur de vue racine.

Au lieu de cela, la stratégie de @Chad M. d'utiliser le UINavigationControllerDelegateest bonne, et voici une solution plus complète. Pas:

  1. Sous-classe UINavigationController
  2. Mettre en œuvre le -navigationController:willShowViewController:animated méthode pour afficher ou masquer la barre de navigation selon qu'elle affiche le contrôleur de vue racine
  3. Substituez les méthodes d'initialisation pour définir la sous-classe UINavigationController comme son propre délégué

Le code complet de cette solution se trouve dans ce Gist . Voici l' navigationController:willShowViewController:animatedimplémentation:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    /* Hide navigation bar if root controller */
    if ([viewController isEqual:[self.viewControllers firstObject]]) {
        [self setNavigationBarHidden:YES animated:animated];
    } else {
        [self setNavigationBarHidden:NO animated:animated];
    }
}
chasseurs
la source
2
C'est une réponse plus appropriée que celle acceptée
Pavel Gurov
14

dans Swift 3:

override func viewWillAppear(_ animated: Bool) {
    navigationController?.navigationBar.isHidden = true
    super.viewWillAppear(animated)
}


override func viewWillDisappear(_ animated: Bool) {
    if (navigationController?.topViewController != self) {
        navigationController?.navigationBar.isHidden = false
    }
    super.viewWillDisappear(animated)
}
Eugene Braginets
la source
pourriez-vous expliquer pourquoi vous vérifiez! = self?
Kitson
2
@Kitson, vérifiez la réponse de l'utilisateur486646: un léger ajustement que j'ai dû apporter aux autres réponses consiste à afficher la barre dans viewWillDisappear uniquement si la raison de sa disparition est due à un élément de navigation poussé dessus. En effet, la vue peut disparaître pour d'autres raisons. Donc, je ne dévoile la barre que si cette vue n'est plus la plus
haute
Il semble que si vous utilisez le, navcontroller.navagationBarHiddenil cassera tout le contrôleur de navigation (pas de glisser d'avant en arrière). Pour le faire fonctionner, j'ai utilisé à la navigationController?.navigationBar.hiddenplace. Le balayage fonctionne toujours et ne laisse pas d'espace vide car il semble être à l'intérieur d'une vue de pile ou quelque chose
Sirens
8

Donne mon crédit à la réponse de @ chad-m.

Voici la version Swift:

  1. Créer un nouveau fichier MyNavigationController.swift

import UIKit

class MyNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        if viewController == self.viewControllers.first {
            self.setNavigationBarHidden(true, animated: animated)
        } else {
            self.setNavigationBarHidden(false, animated: animated)
        }
    }

}
  1. Définissez votre classe UINavigationController dans StoryBoard sur MyNavigationController C'est tout!MyNavigationController

Différence entre la réponse de chad-m et la mienne:

  1. Héritez de UINavigationController pour ne pas polluer votre rootViewController.

  2. utilisez self.viewControllers.firstplutôt que homeViewController, donc vous ne ferez pas cela 100 fois pour vos 100 UINavigationControllers dans 1 StoryBoard.

AI Lion
la source
Pensez que c'est la réponse la plus claire. Merci
DaSilva
6

Après plusieurs essais, voici comment je l'ai fait fonctionner pour ce que je voulais. Voilà ce que j'essayais. - J'ai une vue avec une image. et je voulais que l'image passe en plein écran. - J'ai aussi un contrôleur de navigation avec une tabBar. Je dois donc cacher ça aussi. - De plus, ma principale exigence n'était pas seulement de se cacher, mais aussi d'avoir un effet de décoloration lors de l'affichage et de la dissimulation.

C'est ainsi que je l'ai fait fonctionner.

Étape 1 - J'ai une image et l'utilisateur appuie une fois sur cette image. Je capture ce geste et le pousse dans le nouveau imageViewController, c'est dans le imageViewController, je veux avoir une image plein écran.

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {  
NSLog(@"Single tap");
ImageViewController *imageViewController =
[[ImageViewController alloc] initWithNibName:@"ImageViewController" bundle:nil];

godImageViewController.imgName  = // pass the image.
godImageViewController.hidesBottomBarWhenPushed=YES;// This is important to note. 

[self.navigationController pushViewController:godImageViewController animated:YES];
// If I remove the line below, then I get this error. [CALayer retain]: message sent to deallocated instance . 
// [godImageViewController release];
} 

Étape 2 - Toutes ces étapes ci-dessous sont dans ImageViewController

Étape 2.1 - Dans ViewDidLoad, affichez la barre de navigation

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"viewDidLoad");
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}

Étape 2.2 - Dans viewDidAppear, configurez une tâche de minuterie avec retard (je l'ai définie pour un délai de 1 seconde). Et après le délai, ajoutez un effet de décoloration. J'utilise alpha pour utiliser la décoloration.

- (void)viewDidAppear:(BOOL)animated
{
NSLog(@"viewDidAppear");

myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self     selector:@selector(fadeScreen) userInfo:nil repeats:NO];
}

- (void)fadeScreen
{
[UIView beginAnimations:nil context:nil]; // begins animation block
[UIView setAnimationDuration:1.95];        // sets animation duration
self.navigationController.navigationBar.alpha = 0.0;       // Fades the alpha channel of   this view to "0.0" over the animationDuration of "0.75" seconds
[UIView commitAnimations];   // commits the animation block.  This Block is done.
}

étape 2.3 - Sous viewWillAppear, ajoutez un geste singleTap à l'image et rendez la barre de navigation translucide.

- (void) viewWillAppear:(BOOL)animated
{

NSLog(@"viewWillAppear");


NSString *path = [[NSBundle mainBundle] pathForResource:self.imgName ofType:@"png"];

UIImage *theImage = [UIImage imageWithContentsOfFile:path];

self.imgView.image = theImage;

// add tap gestures 
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
[self.imgView addGestureRecognizer:singleTap];  
[singleTap release];  

// to make the image go full screen
self.navigationController.navigationBar.translucent=YES;
}

- (void)handleTap:(UIGestureRecognizer *)gestureRecognizer 
{ 
 NSLog(@"Handle Single tap");
 [self finishedFading];
  // fade again. You can choose to skip this can add a bool, if you want to fade again when user taps again. 
 myTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self  selector:@selector(fadeScreen) userInfo:nil repeats:NO];
 }

Étape 3 - Enfin viewWillDisappear, assurez-vous de remettre tous les trucs

- (void)viewWillDisappear: (BOOL)animated 
{ 
self.hidesBottomBarWhenPushed = NO; 
self.navigationController.navigationBar.translucent=NO;

if (self.navigationController.topViewController != self)
{
    [self.navigationController setNavigationBarHidden:NO animated:animated];
}

[super viewWillDisappear:animated];
}
verma
la source
4

Si quelqu'un a encore des problèmes avec le bug d'annulation de balayage rapide comme @fabb l'a commenté dans la réponse acceptée.

Je parviens à résoudre ce problème en outrepassant viewDidLayoutSubviews, viewWillAppear/viewWillDisappearcomme indiqué ci-dessous:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
}

//*** This is required to fix navigation bar forever disappear on fast backswipe bug.
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.navigationController?.setNavigationBarHidden(false, animated: false)
}

Dans mon cas, je remarque que c'est parce que le contrôleur de vue racine (où nav est caché) et le contrôleur de vue poussé (nav est affiché) ont différents styles de barre d'état (par exemple sombre et clair). Au moment où vous démarrez le balayage arrière pour faire apparaître le contrôleur de vue, il y aura une animation de couleur de barre d'état supplémentaire. Si vous relâchez votre doigt pour annuler la pop interactive, alors que l'animation de la barre d'état n'est pas terminée , la barre de navigation a disparu pour toujours!

Cependant, ce bogue ne se produit pas si les styles de barre d'état des deux contrôleurs de vue sont identiques.

aunnnn
la source
1

Si vous voulez masquer complètement la barre de navigation dans le contrôleur, une solution beaucoup plus propre consiste à avoir, dans le contrôleur racine, quelque chose comme:

@implementation MainViewController
- (void)viewDidLoad {
    self.navigationController.navigationBarHidden=YES;
    //...extra code on view load  
}

Lorsque vous poussez une vue enfant dans le contrôleur, la barre de navigation reste masquée; si vous souhaitez l'afficher uniquement dans l'enfant, vous ajouterez le code pour l'afficher it(self.navigationController.navigationBarHidden=NO;)dans le viewWillAppearrappel, et de même le code pour le masquerviewWillDisappear

Alex
la source
0

La mise en œuvre la plus simple peut consister à demander à chaque contrôleur de vue de spécifier si sa barre de navigation est masquée ou non dans sa viewWillAppear:animated:méthode. La même approche fonctionne bien pour masquer / afficher la barre d'outils:

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setToolbarHidden:YES/NO animated:animated];
    [super viewWillAppear:animated];
}
SteveCaine
la source
En fait, ma suggestion n'a de sens que pour la barre d'outils, car masquer la barre de navigation sans appel correspondant pour montrer qu'elle empêcherait les utilisateurs de revenir en arrière à partir de la vue actuelle.
SteveCaine
0

Masquer la barre de navigation uniquement sur la première page peut également être réalisé via le storyboard. Sur le storyboard, goto Navigation Controller Scene-> Navigation Bar . Et sélectionnez la propriété ' Hidden ' dans l' inspecteur Attributs . Cela masquera la barre de navigation à partir du premier viewcontroller jusqu'à ce qu'elle soit visible pour le viewcontroller requis.

La barre de navigation peut être redéfinie comme visible dans le rappel ViewWillAppear de ViewController.

-(void)viewWillAppear:(BOOL)animated {

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];                                                  
}
RSG
la source
0

Swift 4:

Dans le contrôleur de vue, vous souhaitez masquer la barre de navigation.

override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
    super.viewWillAppear(animated)
}

override func viewWillDisappear(_ animated: Bool) {
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
    super.viewWillDisappear(animated)
}
John Riselvato
la source
-1

En implémentant ce code dans votre ViewController, vous pouvez obtenir cet effet. En fait, l'astuce est de masquer la barre de navigation lorsque ce contrôleur est lancé

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [super viewWillAppear:animated];
}

et afficher la barre de navigation lorsque l'utilisateur quitte cette page faire ceci est viewWillDisappear

- (void)viewWillDisappear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [super viewWillDisappear:animated];
}
Dhiru
la source