Obtenir la hauteur de la barre de navigation par programme

131

Je sais que la présence du contrôleur more view (barre de navigation) fait baisser l'UIView de sa hauteur. Je sais aussi que cette hauteur = 44px. J'ai également découvert que cette poussée vers le bas maintient le [self.view].frame.origin.y = 0.

Alors, comment puis-je déterminer la hauteur de cette barre de navigation, autre que de simplement la définir sur une constante?

Ou, version plus courte, comment puis-je déterminer que mon UIView s'affiche avec la barre de navigation en haut?


L'ampoule a commencé à s'allumer. Malheureusement, je n'ai pas découvert de manière uniforme de corriger le problème, comme décrit ci-dessous.

Je crois que tout mon problème est centré sur mes masques de redimensionnement automatique. Et la raison pour laquelle j'ai conclu que les mêmes symptômes existent, avec ou sans UIWebView. Et ce symptôme est que tout est pêche pour Portrait. Pour Landscape, l'UIButton le plus bas apparaît derrière la TabBar.

Par exemple, sur un UIView, j'ai, de haut en bas:

UIView - les deux ressorts sont réglés (cas par défaut) et pas d'entretoises

UIScrollView - Si je place les deux ressorts et efface tout le reste (comme l'UIView), alors l'UIButton empiète sur l'objet immédiatement au-dessus. Si je nettoie tout, alors UIButton est OK, mais le truc tout en haut se cache derrière le StatusBar.

UILabel et UIImage suivant verticalement - ensemble de jambes de force supérieur, flexible partout ailleurs

Juste pour compléter l'image pour les quelques-uns qui ont une UIWebView:

UIWebView - Struts: haut, gauche, droite Ressorts: les deux

UIButton - rien de fixe, c'est-à-dire flexible partout

Bien que mon ampoule soit faible, il semble y avoir de l'espoir.


Veuillez rester avec moi car j'avais besoin de plus d'espace que celui prévu pour une courte réponse.

Merci d'essayer de comprendre ce que je pêche vraiment ... alors voilà.

1) Chaque UIViewController (une application TabBar) a une UIImage, du texte et tout ce qui se trouve en haut. Un autre dénominateur commun est un UIButton en bas. Sur certains UIViewControllers, j'ai un UIWebView au-dessus de l'UIButton.

Donc, UIImage, texte, etc. UIWebView (sur CERTAINS) UIButton

Tout ce qui précède est entouré d'un UIScrollView.

2) Pour ceux qui ont une UIWebView, son autoresizingMask ressemble à:

   
   |
   

   ^
   |
   |

| - | ← ---- → | - | | | V Le masque de l'UIButton n'a rien de défini, c'est-à-dire flexible partout

Dans mon -viewDidLoad, j'appelle mon -repositionSubViews dans lequel je fais ce qui suit:

S'il n'y a pas d'UIWebView, je ne fais rien d'autre que de centrer l'UIButton que j'ai placé avec IB.

Si j'ai un UIWebView, alors je détermine son * contenu * Hauteur et définissez son cadre pour englober tout le contenu.

UIScrollView *scrollViewInsideWebView = [[webView_ subviews] lastObject];
webViewContentHeight = scrollViewInsideWebView.contentSize.height;
[webView_ setFrame:CGRectMake(webViewOriginX, webViewOriginY,
                          sameWholeViewScrollerWidth, webViewContentHeight)]

Une fois que je fais cela, je pousse par programme l'UIButton vers le bas afin qu'il se retrouve placé sous UIWebView.

Tout fonctionne, jusqu'à ce que je le fasse pivoter de Portrait en Paysage.

J'appelle mon -repositionSubViews dans mon -didRotateFromInterfaceOrientation.

Pourquoi la hauteur du contenu de mon UIWebView ne change-t-elle pas avec la rotation?.

De Portrait à Paysage, la largeur du contenu doit s'étendre et la hauteur du contenu doit être réduite. Il fait visuellement comme il se doit, mais pas selon mon NSLog.

Quoi qu'il en soit, avec ou sans UIWebView, le bouton dont j'ai parlé se déplace sous la TabBar en mode Paysage mais il ne défilera pas pour être vu. Je le vois derrière le TabBar quand je fais défiler "vigoureusement", mais ensuite il "retombe" derrière le TabBar.

En bout de ligne, c'est la raison pour laquelle j'ai posé des questions sur la hauteur de la TabBar et de la NavigationBar car la TabBar se plante au bas de l'UIView et la NavigationBar pousse l'UIView vers le bas.

Maintenant, je vais ajouter un commentaire ou deux ici parce qu'ils n'auraient pas eu de sens plus tôt.

Sans UIWebView, je laisse tout tel quel comme le voit IB.

Avec un UIWebView, j'augmente le frame.height de l'UIWebView à son contentHeight et ajuste également vers le haut la hauteur de l'UIScrollView environnant qui entoure toutes les sous-vues.

Bien, tu l'as maintenant.

Krunal
la source

Réponses:

258

Faites quelque chose comme ça?

    NSLog(@"Navframe Height=%f",
        self.navigationController.navigationBar.frame.size.height);

La version swift se trouve ici


METTRE À JOUR

iOS 13

Comme le statusBarFrameétait obsolète dans, iOS13vous pouvez utiliser ceci:

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}
Somme
la source
Merci merci. MAIS, maintenant que vous avez résolu ce problème, comment déterminer si le NavigationController, alias MoreViewController, s'affiche pour mon application de barre d'onglets.
Je ne comprends pas tout à fait ce que vous essayez de dire. Essayez-vous de savoir si MoreViewController s'affiche? (Si oui, que voulez-vous faire?) Et si non, pourriez-vous clarifier ce que vous voulez dire exactement?
Somme du
J'ai relu votre question et je n'ai toujours pas compris ce que vous voulez faire? Si vous voulez faire quelque chose lorsque la vue apparaît, vous devez insérer le code dans viewDidAppear. Si vous clarifiez un peu, il serait plus facile de comprendre ce que vous voulez faire.
Somme du
2
Je sais que cela ne répond pas à la question qu'il a posée, mais il semble qu'il cherchait à voir si la barre de navigation était masquée ou non. Si tel est le cas, il aurait pu utiliser self.navigationController.navigationBarHidden Hope pleinement, cela aide quelqu'un :)
taylorcressy
2
Dans iOS 7+, vous devrez peut-être également prendre en compte la barre d'état de 20 pixels en fonction de votre application
Slayter
94

Avec l'iPhone-X, la hauteur de la barre supérieure (barre de navigation + barre d'état) est modifiée (augmentée).

Essayez ceci si vous voulez la hauteur exacte de la barre supérieure (barre de navigation + barre d'état):

METTRE À JOUR

iOS 13

Comme le statusBarFrameétait obsolète dans, iOS13vous pouvez utiliser ceci:

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

Objectif c

CGFloat topbarHeight = ([UIApplication sharedApplication].statusBarFrame.size.height +
       (self.navigationController.navigationBar.frame.size.height ?: 0.0));

Swift 4

let topBarHeight = UIApplication.shared.statusBarFrame.size.height +
        (self.navigationController?.navigationBar.frame.height ?? 0.0)

Pour plus de facilité, essayez cette extension UIViewController

extension UIViewController {

    /**
     *  Height of status bar + navigation bar (if navigation bar exist)
     */

    var topbarHeight: CGFloat {
        return UIApplication.shared.statusBarFrame.size.height +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

Swift 3

let topBarHeight = UIApplication.sharedApplication().statusBarFrame.size.height +
(self.navigationController?.navigationBar.frame.height ?? 0.0)

Krunal
la source
3
La réponse Swift 4 renvoie une hauteur de 0 pour moi.
Chewie The Chorkie
61

Version Swift :

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
Roi-sorcier
la source
Renvoie toujours 44. Comment connaître la taille réduite (44) ou la taille développée (grands titres) ??? Dynamiquement, bien sûr. (Je sais ce que cela mesure)
Markus
6

Avez-vous essayé cela?

let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
Keaz
la source
5

Prise en charge d'iOS 13 et inférieur:

extension UIViewController {

    var topbarHeight: CGFloat {
        if #available(iOS 13.0, *) {
            return (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
                (self.navigationController?.navigationBar.frame.height ?? 0.0)
        } else {
            let topBarHeight = UIApplication.shared.statusBarFrame.size.height +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
            return topBarHeight
        }
    }
}
Hitesh Surani
la source
4
UIImage*image = [UIImage imageNamed:@"logo"];

float targetHeight = self.navigationController.navigationBar.frame.size.height;
float logoRatio = image.size.width / image.size.height;
float targetWidth = targetHeight * logoRatio;

UIImageView*logoView = [[UIImageView alloc] initWithImage:image];
// X or Y position can not be manipulated because autolayout handles positions.
//[logoView setFrame:CGRectMake((self.navigationController.navigationBar.frame.size.width - targetWidth) / 2 , (self.navigationController.navigationBar.frame.size.height - targetHeight) / 2 , targetWidth, targetHeight)];
[logoView setFrame:CGRectMake(0, 0, targetWidth, targetHeight)];
self.navigationItem.titleView = logoView;

// How much you pull out the strings and struts, with autolayout, your image will fill the width on navigation bar. So setting only height and content mode is enough/
[logoView setContentMode:UIViewContentModeScaleAspectFit];

/* Autolayout constraints also can not be manipulated since navigation bar has  immutable constraints
self.navigationItem.titleView.translatesAutoresizingMaskIntoConstraints = false;

NSDictionary*metricsArray = @{@"width":[NSNumber numberWithFloat:targetWidth],@"height":[NSNumber numberWithFloat:targetHeight],@"margin":[NSNumber numberWithFloat:20]};
NSDictionary*viewsArray = @{@"titleView":self.navigationItem.titleView};

[self.navigationItem.titleView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>margin=)-H:[titleView(width)]-(>margin=)-|" options:NSLayoutFormatAlignAllCenterX metrics:metricsArray views:viewsArray]];
[self.navigationItem.titleView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[titleView(height)]" options:0 metrics:metricsArray views:viewsArray]];

NSLog(@"%f", self.navigationItem.titleView.width );
*/

Donc tout ce dont nous avons réellement besoin est

UIImage*image = [UIImage imageNamed:@"logo"];
UIImageView*logoView = [[UIImageView alloc] initWithImage:image];
float targetHeight = self.navigationController.navigationBar.frame.size.height;
[logoView setFrame:CGRectMake(0, 0, 0, targetHeight)];
[logoView setContentMode:UIViewContentModeScaleAspectFit];

self.navigationItem.titleView = logoView;
ironik sütlaç
la source
2

Mon application a quelques vues qui nécessitaient une barre de navigation personnalisée dans l'interface utilisateur pour l'apparence, mais sans contrôleur de navigation. Et l'application doit prendre en charge la version iOS antérieure à iOS 11, de sorte que le guide pratique de disposition de la zone de sécurité ne peut pas être utilisé, et je dois ajuster la position et la hauteur de la barre de navigation par programme.

J'ai attaché la barre de navigation directement à sa vue supervisée, en ignorant le guide de disposition de la zone de sécurité comme mentionné ci-dessus. Et la hauteur de la barre d'état peut être récupérée facilement depuis UIApplication, mais la hauteur de la barre de navigation par défaut est vraiment pénible ...

Cela m'a frappé pendant près d'une demi-nuit, avec un certain nombre de recherches et de tests, jusqu'à ce que je reçoive finalement l'indice d'un autre message (qui ne fonctionne pas pour moi cependant), que vous pourriez réellement obtenir la hauteur de UIView.sizeThatFits (), comme ça :

- (void)viewWillLayoutSubviews {
    self.topBarHeightConstraint.constant = [UIApplication sharedApplication].statusBarFrame.size.height;
    self.navBarHeightConstraint.constant = [self.navigationBar sizeThatFits:CGSizeZero].height;

    [super viewWillLayoutSubviews];    
}

Enfin, une barre de navigation parfaite qui ressemble exactement à celle intégrée!

Stephen Liu
la source
2

Si vous ne voulez obtenir que la navigationBarhauteur, c'est simple:

extension UIViewController{
   var navigationBarHeight: CGFloat {
       return self.navigationController?.navigationBar.frame.height ?? 0.0
   }
}

Cependant, si vous avez besoin de la hauteur de premier ordre de l'iPhone, vous n'avez pas besoin d'obtenir la navigationBarhauteur et de lui ajouter la statusBarhauteur, vous pouvez simplement appeler safeAreaInsetsc'est pourquoi exister.

self.view.safeAreaInsets.top
mojtaba al moussawi
la source
1

L'ampoule a commencé à s'allumer. Malheureusement, je n'ai pas découvert de manière uniforme de corriger le problème, comme décrit ci-dessous.

Je crois que tout mon problème est centré sur mes masques de redimensionnement automatique. Et la raison pour laquelle j'ai conclu que les mêmes symptômes existent, avec ou sans UIWebView. Et ce symptôme est que tout est pêche pour Portrait. Pour Landscape, l'UIButton le plus bas apparaît derrière la TabBar.

Par exemple, sur un UIView, j'ai, de haut en bas:

UIView - les deux ressorts sont réglés (cas par défaut) et aucune entretoise

UIScrollView - Si je place les deux ressorts et efface tout le reste (comme l'UIView), alors l'UIButton empiète sur l'objet immédiatement au-dessus. Si je nettoie tout, alors UIButton est OK, mais le truc tout en haut se cache derrière le StatusBar.

UILabel et UIImage suivant verticalement - ensemble de jambes de force supérieur, flexible partout ailleurs

Juste pour compléter l'image pour les quelques-uns qui ont une UIWebView:

UIWebView - Struts: haut, gauche, droite Ressorts: les deux

UIButton - rien de fixe, c'est-à-dire flexible partout

Bien que mon ampoule soit faible, il semble y avoir de l'espoir.


la source
Réglez la jambe de force supérieure et réglez les deux ressorts de l'UIWebView - problème résolu et merci beaucoup. En fait, mon seul problème restant est de concevoir ces graphiques maudits @ 2X, etc. J'utilise GraphicConverter d'une manière très simple et cela fonctionne très bien pour la conception de pages Web. Mais tous ces trucs 30px, 57px - je vais au moins en territoire inconnu pour moi.
1

Voici le début de ma réponse à votre mise à jour:

Pourquoi la hauteur du contenu de mon UIWebView ne change-t-elle pas avec la rotation?.

Serait-ce parce que votre redimensionnement automatique n'a pas le masque de redimensionnement automatique pour toutes les directions?

Une autre suggestion avant de revenir pour cela, pourriez-vous utiliser une barre d'outils pour vos besoins. C'est un peu plus simple, sera toujours en bas, tourne / positionne automatiquement. Vous pouvez le cacher / l'afficher à volonté, etc. Un peu comme ça: http://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg

Vous avez peut-être envisagé cette option, mais vous l'avez simplement lancée.

Une autre idée, pourriez-vous détecter l'orientation à partir de laquelle vous effectuez une rotation et placer simplement le bouton par programme pour ajuster la barre d'onglets. (Ceci est possible avec le code)

Somme
la source
Après environ 2 semaines pour résoudre ce problème, j'ai décidé que le "problème" était rendu plus difficile en plaçant un UIButton SOUS la sous-vue UIWebView. Alors, j'ai mis le bouton AU-DESSUS. Franchement, ça n'a pas l'air "juste" de cette façon ... mais ça marche maintenant SORT OF. CI-DESSOUS ou AU-DESSUS, l'UIWebView a placé la jambe de force supérieure et juste le ressort horizontal. BTW, c'est le contentHeight de l'UIWebView qui ne change pas avec la rotation.
0

J'ai utilisé:

let originY: CGFloat = self.navigationController!.navigationBar.frame.maxY

Fonctionne très bien si vous souhaitez obtenir la hauteur de la barre de navigation ET son origine Y.

user3332228
la source
0

Swift 5

Si vous souhaitez également envisager le safeArea:

 let height = navigationController?.navigationBar.frame.maxY  
Kivia Martins Brito
la source
0

Extension Handy Swift 4, au cas où cela serait utile à quelqu'un d'autre. Fonctionne même si le contrôleur de vue actuel n'affiche pas de barre de navigation.

import UIKit

extension UINavigationController {
  static public func navBarHeight() -> CGFloat {
    let nVc = UINavigationController(rootViewController: UIViewController(nibName: nil, bundle: nil))
    let navBarHeight = nVc.navigationBar.frame.size.height
    return navBarHeight
  }
}

Usage:

UINavigationController.navBarHeight()
Nom de code: Duchesse
la source