web-dev-qa-db-fra.com

Comment empêcher la barre d'état de chevaucher le contenu avec hidesBarsOnSwipe défini sur UINavigationController?

J'essaie d'utiliser la nouvelle fonctionnalité ajoutée dans iOS 8 - masquer la barre de navigation pendant que l'utilisateur fait défiler la vue du tableau (similaire à ce que fait Safari mobile). Je mets la propriété hidesBarsOnSwipe de UINavigationController à YES dans viewDidAppear méthode de UITableViewController:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if([self.navigationController respondsToSelector:@selector(hidesBarsOnSwipe)]) {
        self.navigationController.hidesBarsOnSwipe = YES;
    }
}

La barre de navigation se cache lorsque la vue défile. Jusqu'ici tout va bien. Mais la barre d'état est toujours visible et le contenu de ma vue tabulaire apparaît à travers elle, ce qui semble laid:

enter image description here

J'ai essayé de définir edgesForExtendedLayout sur UIEdgeRectNone ou d'ajuster le contentInset de la vue de table, mais cela n'a pas aidé. Existe-t-il une autre solution pour masquer la barre d'état avec la barre de navigation ou la rendre opaque?

34
Michał Ciuba

À partir de la réponse d'Anas, j'ai une solution qui fonctionne (je suppose que tableViewController est votre instance de UITableViewController):

Dans une sous-classe UINavigationController (ou potentiellement à partir de tableViewController):

- (void)viewDidLoad {
    if ([self respondsToSelector:@selector(barHideOnSwipeGestureRecognizer)]) {
        // iOS 8+
        self.hidesBarsOnSwipe = YES;
        [self.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
    }
}

- (void)swipe:(UISwipeGestureRecognizer *)recognizer {
    BOOL shouldHideStatusBar = self.navigationController.navigationBar.frame.Origin.y < 0;
    tableViewController.hideStatusBar = shouldHideStatusBar;
    [UIView animateWithDuration:0.2 animations:^{
        [tableViewController setNeedsStatusBarAppearanceUpdate];
    }];
}

Dans votre tableViewController:

@property(nonatomic, getter = shouldHideStatusBar) BOOL hideStatusBar;

- (BOOL)prefersStatusBarHidden {
    return [self shouldHideStatusBar];
}

Faites-moi savoir si cela ne fonctionne pas pour vous. Quelques choses non évidentes:

  • self.navigationController.navigationBar.frame.Origin.y était -44 (la hauteur négative de la barre de navigation) lorsqu'il était masqué et 20 (la hauteur de la barre d'état) lorsqu'il était visible. Il n'y avait pas d'intermédiaire, même pendant les animations, donc une valeur négative == cachée et une valeur non négative == visible.
  • Le contrôleur de vue enfant est celui qui a demandé si la barre d'état doit être masquée ou non. Dans mon cas, j'ai un UIViewController dans un UINavigationController dans un UITabBarController, et cela n'a pas fonctionné tant que je n'ai pas remplacé prefersStatusBarHidden sur le UIViewController.
  • Puisqu'une barre d'état cachée n'a pas de cadre, votre contenu peut augmenter de 20 points à moins que vous n'encapsuliez l'appel à setNeedsStatusBarAppearanceUpdate dans un bloc d'animation.
  • Espérons que la syntaxe soit correcte; J'ai rétroporté cela à partir de mon code Swift.
30
Andrew

En fait, c'est assez facile à faire. Il vous suffit de connecter la propriété de navigation isNavigationBarHidden à la barre d'état.

Objectif-C

- (BOOL)prefersStatusBarHidden {
    return self.navigationController.isNavigationBarHidden;
}

Swift <= 2.

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}

Swift 3.

override var prefersStatusBarHidden: Bool {
    return navigationController?.isNavigationBarHidden ?? false
}

Et assurez-vous que "Afficher l'apparence de la barre d'état basée sur le contrôleur" = "OUI" dans le fichier .plist de votre application.

39
iOSergey

Cette nouvelle propriété est fournie avec son barHideOnSwipeGestureRecognizer.

À partir de Référence de classe UINavigationController :

Vous pouvez apporter des modifications à l'outil de reconnaissance des gestes selon vos besoins, mais vous ne devez pas modifier son délégué et vous ne devez pas supprimer l'objet cible et l'action par défaut qui sont configurés avec lui. N'essayez pas de remplacer cet identificateur de gestes en remplaçant la propriété.

Mais vous pouvez ajouter une cible:

[self.navigationController setHidesBarsOnSwipe:YES];
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipeGesture:)];

... et faites ce que vous voulez dans le rappel:

- (void)swipeGesture:(UIPanGestureRecognizer*)gesture
{
    // Tweak the status bar
}

Vous devrez peut-être activer manuellement les états de geste, déterminer quand masquer/afficher la barre d'état, etc. J'espère que cela vous aidera!

8
Anas

La réponse de @iOSergey fonctionne parfaitement!

Voici la solution dans Swift 1.2. Ajoutez le code suivant au fichier .Swift des vues:

override func prefersStatusBarHidden() -> Bool {

    return self.navigationController!.navigationBarHidden as Bool

}
3

Si vous souhaitez masquer la barre d'état avec une animation:

override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
    return .Slide
}

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}
3
Tai Le

Après beaucoup de lutte, j'ai finalement pu résoudre ce problème.

  1. Remplacez TableViewController par UIViewController
  2. Faites glisser une TableView vers UIViewController et alignez-la juste sous la barre de navigation dans le main.storyboard
  3. Ajoutez des contraintes manquantes.
  4. cliquez sur tableview et inspectez les contraintes
  5. définir l'espace inférieur à: superview à 0
  6. définissez l'espace de fin sur superview à 0
  7. définir l'espace principal à superview à 0
  8. définissez "Aligner le haut sur: Guide de mise en page supérieur. Haut sur 0 (très important)

Ajoutez le code suivant à la fonction viewDidLoad de UIViewController:

// Créer un fond de couleur unie pour la barre d'état (dans Swift Code)

laissez statusFrame = CGRectMake (0.0, 0, self.view.bounds.size.width,
UIApplication.sharedApplication (). StatusBarFrame.size.height)

var statusBar = UIView (cadre: statusFrame)

statusBar.backgroundColor = UIColor.whiteColor ()

self.view.addSubview (statusBar)

Ce que vous faites est de créer une barre pleine juste en dessous de la barre de navigation. Lorsque la barre de navigation se déplace vers le haut, la barre pleine se déplace également vers le haut et juste derrière la barre d'état.

Le seul problème est que lorsque vous faites pivoter les côtés de l'écran, la barre blanche est toujours là même si la barre d'état disparaît.

2
John Chen

D'accord, j'ai passé toute la journée à faire cela, j'espère que cela aidera certaines personnes. Il y a un barHideOnSwipeGestureRecognizer. Vous pouvez donc créer un écouteur pour le UIPanGesture correspondant, en notant que si la barre de navigation est masquée, son origine y est -44.0; sinon, c'est 0 (pas 20 car nous avons caché la barre d'état!).

Dans votre contrôleur de vue (Swift 2):

 // Declare at beginning
var curFramePosition: Double!
var showStatusBar: Bool = true
self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")

...

override func viewDidLoad(){
    self.navigationController?.hidesBarsOnSwipe = true
  curFramePosition = 0.0 // Not hidden
  self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")
  ...
}

func didSwipe(swipe: UIPanGestureRecognizer){
    // Visible to hidden
    if curFramePosition == 0 && self.navigationController?.navigationBar.frame.Origin.y == -44 {
        curFramePosition = -44
        showStatusBar = false
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
    // Hidden to visible
    else if curFramePosition == -44 && self.navigationController?.navigationBar.frame.Origin.y == 0 {
        curFramePosition = 0
        showStatusBar = true
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
}

override func prefersStatusBarHidden() -> Bool {
    if showStatusBar{
        return false
    }
    return true
}
1
goodcow

Une autre façon de le faire consiste simplement à ajouter une autre vue (au-dessus de la vue de table ou de la collection ou de la vue Web ou de la vue de défilement ou autre) et de définir la contrainte supérieure de la vue sur "Superview.Top" et sa contrainte inférieure sur "Top Layout Guide.Bottom", définissez la afficher la couleur d'arrière-plan et c'est tout, vous pouvez même tout faire dans Interface Builder sans aucun code. Et si vous souhaitez répondre à cet événement, vous pouvez ajouter un observateur de chemins de touches au changement de limites de la vue, ou sous-classer la vue et remplacer son régleur de limites ...

0
Oleg Sherman

Vous devez connecter la navigation isNavigationBarHidden à la barre d'état.

    return self.navigationController.isNavigationBarHidden;
0