web-dev-qa-db-fra.com

Moyen approprié de masquer la barre d'état sur iOS, avec animation et redimensionnement de la vue racine

Considérons un contrôleur de vue qui doit faire glisser (ou masquer) la barre d'état lorsqu'un bouton est cliqué.

- (void) buttonClick:(id)sender
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES
                                            withAnimation:UIStatusBarAnimationSlide];
}

Ce qui précède masque efficacement la barre d'état, mais ne redimensionne pas la vue racine de manière appropriée, laissant un espace de 20 pixels au-dessus.

Ce à quoi je m'attendais, c'est que la vue racine se développe sur l'espace précédemment utilisé par la barre d'état (animé, de même durée que l'animation de la barre d'état).

Quelle est la bonne façon de faire cela?

(Je suis conscient qu'il y a beaucoup de questions similaires, mais je n'ai rien trouvé à propos de masquer la barre d'état à la demande plutôt que de le masquer pour afficher un nouveau contrôleur de vue.)

L'approche "force brute"

Évidemment, les travaux suivants ...

[[UIApplication sharedApplication] setStatusBarHidden:YES
                                        withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    CGRect frame = self.view.frame;
    frame.Origin.y -= 20;
    frame.size.height += 20;
    self.view.frame = frame;
}];

... mais a des inconvénients:

  • Hardcodes la durée de l'animation de diapositive
  • Code la hauteur de la barre d'état
  • La vue racine Origine reste à (0, -20). J'aime que mes cadres commencent à (0,0) autant que possible.

Ce que j'ai déjà essayé

  • Assurez-vous que le masque de redimensionnement automatique de la vue racine a UIViewAutoresizingFlexibleTopMargin et UIViewAutoresizingFlexibleHeight.
  • Appelé [self.view setNeedsLayout] après avoir masqué la barre d'état.
  • Appelé [self.view setNeedsDisplay] après avoir masqué la barre d'état.
  • Définissez wantsFullScreenLayout sur YES avant et après le masquage de la barre d'état.
32
hpique

Cela fonctionne bien et n'a rien codé en dur .

CGRect appFrame = [[UIScreen mainScreen] applicationFrame];

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    self.navigationController.navigationBar.frame = self.navigationController.navigationBar.bounds;
    self.view.window.frame = CGRectMake(0, 0, appFrame.size.width, appFrame.size.height);
}];
16
Lefteris

Pour ceux qui essaient d'implémenter ceci avec une apparence de barre d'état basée sur le contrôleur de vue, vous devez implémenter la méthode prefersStatusBarHidden dans votre contrôleur de vue

 - (BOOL)prefersStatusBarHidden
{
    // If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
    return (self.statusBarHidden) ? YES : NO;
}

Et puis, dans votre méthode de clic sur le bouton:

- (void) buttonClick:(id)sender
{
    // Switch BOOL value
    self.statusBarHidden = (self.statusBarHidden) ? NO : YES;

    // Update the status bar
    [UIView animateWithDuration:0.25 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
    }];
}

Pour définir le style d'animation, vous utilisez ceci:

-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
    return UIStatusBarAnimationSlide;
}

Et pour personnaliser le style:

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}
23
awfulcode

Vous pouvez présenter, puis fermer le contrôleur de vue modale pour masquer correctement la barre d'état.

- (void)toggleStatusBar {
    BOOL isStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden];
    [[UIApplication sharedApplication] setStatusBarHidden:!isStatusBarHidden];

    UIViewController *vc = [[UIViewController alloc] init];
    [self presentViewController:vc animated:NO completion:nil];
    [self dismissViewControllerAnimated:NO completion:nil];
    [vc release];
}

J'ai utilisé ce code dans la méthode "willAnimateRotationToInterfaceOrientation" pour l'orientation paysage et tout fonctionne correctement. Mais je ne sais pas si cela fonctionnera avec l'animation.

8
Exception

Masquer ou afficher la barre d'état qui redimensionne également la vue: 

-(void)statusBar:(BOOL)status {
UIViewController *rootViewController = self.view.window.rootViewController;
UIView *view = rootViewController.view;

// Hide/Unhide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:status]; // BOOL : YES or NO

// statusBar frame
CGRect statusBarFrame = [UIApplication.sharedApplication statusBarFrame];
// Establish baseline frame
CGRect newViewFrame = self.view.window.bounds;

// Check statusBar frame is worth dodging
if (!CGRectEqualToRect(statusBarFrame, CGRectZero)) {
    UIInterfaceOrientation currentOrientation = rootViewController.interfaceOrientation;
    if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
        // If portrait need to shrink height
        newViewFrame.size.height -= statusBarFrame.size.height;
        if (currentOrientation == UIInterfaceOrientationPortrait) {
            // If not upside-down move down Origin
            newViewFrame.Origin.y += statusBarFrame.size.height;
        }
    } else { // Is landscape 
        // portrait shrink width
        newViewFrame.size.width -= statusBarFrame.size.width;
        if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
            // If the status bar is on the left side of the window move Origin
            newViewFrame.Origin.x += statusBarFrame.size.width;
        }
    }
}
view.frame = newViewFrame; // pass new frame 
}

méthode d'appel (message):

 if ([[UIApplication sharedApplication] isStatusBarHidden]) {
        [self statusBar:NO];
 } else {
        [self statusBar:YES];
 }
7
Shams Ahmed

Je connais un moyen de contourner le problème, mais les inconvénients sont également évidents. Vous pouvez définir self.wantsFullScreenLayout = YES; dans votre viewDidLoad et définir votre fichier xib aussi grand que l'écran (320x480 et 320x568 pour iPhone5). Mais cela signifie également que la zone située sous la barre d'état n'est pas visible. Et, de cette manière, votre vue ne sera pas non plus développée lorsque vous masquez la barre d'état. Vous pouvez envisager cette possibilité si vous n'avez rien à afficher dans la zone de la barre d'état.

0
sunkehappy

Pour plus de commodité, une variante Swift 4 de la réponse de @ awfulcode:

var statusBarHidden = false {
    didSet {
        UIView.animate(withDuration: 0.25) {
            self.setNeedsStatusBarAppearanceUpdate()
        }
    }
}

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .default
}

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    return .fade
}

override var prefersStatusBarHidden: Bool {
    return statusBarHidden
}
0
pinch

Après avoir passé des heures à expérimenter et à chercher une réponse, en particulier cette réponse . Avec un peu de peaufinage, j'ai réussi à le faire, maintenant l'écart supérieur 20px est parti entre la transition!

Supposons que nous ayons un ivar BOOL isStatusBarEnabled qui indiquera si nous devrions avoir la barre d’état cachée ou non (par exemple: en accédant à NSUserDefault pour vérifier boolValueForKey).

Donc, on vérifie d'abord si statusBar est déjà caché ou non via [[UIApplication sharedApplication] isStatusBarHidden], s'il n'est pas caché (== affiché), on le cache! Sinon, faites autrement!

  • Pour corriger 20px lorsque l’état est affiché - mais que la navigation n’est pas correctement poussée, il suffit d’ajouter 20 points à Origin.y sur self.navgigationController.navigationBar.frame.

  • Faites la même chose lorsque nous voulons masquer la barre d’état. Supprimez simplement ces 20 points pour Origin.y sur self.navgigationController.navigationBar.frame, laissez-le donc 0.

Ça y est!

@implementation SomeViewController {
    BOOL isStatusBarEnabled;
}

// ...

- (void)toggleStatusBar
{
    UINavigationBar *navBar = self.navigationController.navigationBar;

    if ([[UIApplication sharedApplication] isStatusBarHidden]) {

        // Change to regular mode
        // Show status bar
        [[UIApplication sharedApplication] setStatusBarHidden:NO
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.3
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.Origin.x, 20, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];

    } else if (![[UIApplication sharedApplication] isStatusBarHidden]) {
        // Change to fullscreen mode
        // Hide status bar
        [[UIApplication sharedApplication] setStatusBarHidden:YES
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.4
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.Origin.x, 0, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];
    }

}

// ...

... puis, dans mon cas, j'ai une clé de réglage permettant à l'utilisateur de choisir d'afficher ou de masquer la barre d'état.

// ...

- (void)onDefaultsChanged:(NSNotification*)aNotification
{

    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
    isStatusBarEnabled = [standardDefaults boolForKey:kStatusBar];

    if (isStatusBarEnabled) {

      if ([[UIApplication sharedApplication] isStatusBarHidden]) {

          // Change to regular mode
          // Show status bar
          [self toggleStatusBar];   

    } else {

        // Change to fullscreen mode
        // Hide status bar
        [self toggleStatusBar];

  }

  // ...
}

c'est tout!

0
Vinh Nguyen