Obtenga programáticamente la altura de la barra de navegación

131

Sé que la presencia del controlador más vista (barra de navegación) empuja hacia abajo la UIView por su altura. También sé que esta altura = 44px. También he descubierto que este empuje hacia abajo mantiene el [self.view].frame.origin.y = 0.

Entonces, ¿cómo determino la altura de esta barra de navegación, además de establecerla en una constante?

O, en una versión más corta, ¿cómo determino que mi UIView se muestra con la barra de navegación en la parte superior?


La bombilla comenzó a encenderse. Desafortunadamente, no he descubierto una forma uniforme de corregir el problema, como se describe a continuación.

Creo que todo mi problema se centra en mis autoresizingMasks. Y la razón por la que he concluido es que existen los mismos síntomas, con o sin UIWebView. Y ese síntoma es que todo es color de rosa para Portrait. Para Landscape, el UIButton más inferior aparece detrás de TabBar.

Por ejemplo, en una UIView, tengo, de arriba a abajo:

UIView: conjunto de muelles (caso predeterminado) y sin puntales

UIScrollView: si configuro los dos resortes y borro todo lo demás (como el UIView), el UIButton se entromete en el objeto que se encuentra inmediatamente encima de él. Si borro todo, UIButton está bien, pero las cosas en la parte superior se esconden detrás de la barra de estado. Configurando solo el puntal superior, el UIButton aparece detrás de la barra de pestañas.

UILabel y UIImage son los siguientes verticalmente: conjunto de puntal superior, flexible en cualquier otro lugar

Solo para completar la imagen para los pocos que tienen un UIWebView:

UIWebView - Struts: arriba, izquierda, derecha Resortes: ambos

UIButton: nada configurado, es decir, flexible en todas partes

Aunque mi bombilla es tenue, parece haber esperanza.


Por favor, tengan paciencia conmigo porque necesitaba más espacio que el previsto para un breve comentario de respuesta.

Gracias por tratar de entender lo que realmente estoy pescando ... así que aquí va.

1) Cada UIViewController (una aplicación TabBar) tiene un UIImage, algo de texto y lo que sea en la parte superior. Otro denominador común es un UIButton en la parte inferior. En algunos de los UIViewControllers tengo un UIWebView sobre el UIButton.

Entonces, UIImage, texto, etc. UIWebView (en ALGUNOS) UIButton

Alrededor de todo lo anterior hay un UIScrollView.

2) Para aquellos que tienen un UIWebView, su autoresizingMask se ve así:

   
   |
   

   ^
   |
   |

| - | ← ---- → | - | El | El | V La máscara de UIButton no tiene nada establecido, es decir, es flexible en todas partes

Dentro de mi -viewDidLoad, llamo a mi -repositionSubViews dentro de la cual hago lo siguiente:

Si no hay UIWebView, no hago nada excepto centrar el UIButton que coloqué con IB.

Si tengo un UIWebView, entonces determino su * contenido * Altura y establezco su marco para encerrar todo el contenido.

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

Una vez que hago eso, presiono programáticamente el botón UIB hacia abajo para que termine colocado debajo de UIWebView.

Todo funciona, hasta que lo gire de vertical a horizontal.

Llamo a mi -repositionSubViews dentro de mi -didRotateFromInterfaceOrientation.

¿Por qué la altura del contenido de mi UIWebView no cambia con la rotación?

De vertical a horizontal, el ancho del contenido debe expandirse y la altura del contenido debe reducirse. Lo hace visualmente como debería, pero no según mi NSLog.

De todos modos, con o sin UIWebView, el botón del que hablé se mueve debajo de la barra de pestañas cuando está en modo horizontal, pero no se desplazará hacia arriba para ser visto. Lo veo detrás de la TabBar cuando me desplazo "vigorosamente", pero luego "retrocede" detrás de la TabBar.

En pocas palabras, esta última es la razón por la que he preguntado sobre la altura de TabBar y NavigationBar porque TabBar se planta en la parte inferior de UIView y NavigationBar empuja a UIView hacia abajo.

Ahora, voy a agregar un comentario o dos aquí porque no tendrían sentido antes.

Sin UIWebView, dejo todo tal como lo ve IB.

Con un UIWebView, aumento el marco de UIWebView.height a su contentHeight y también ajusto hacia arriba la altura del UIScrollView circundante que rodea todas las sub-vistas.

Bueno, ahí lo tienes.

Krunal
fuente

Respuestas:

258

¿Hacer algo como esto?

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

La versión rápida se encuentra aquí


ACTUALIZAR

iOS 13

Como statusBarFramefue desaprobado en iOS13puede usar esto:

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)
    }
}
Suma
fuente
Gracias Gracias. PERO, ahora que ha resuelto ese problema, ¿cómo puedo determinar si el NavigationController, también conocido como MoreViewController, se muestra para mi aplicación de barra de pestañas?
No entiendo lo que estás tratando de decir. ¿Estás tratando de averiguar si se está mostrando MoreViewController? (Si es así, ¿qué quieres hacer?) Y si no, ¿podrías aclarar a qué te refieres exactamente?
Suma
¿Leí tu pregunta nuevamente y aún no entendí lo que quieres hacer? Si desea hacer algo cuando aparece la vista, debe insertar el código en viewDidAppear. Si aclaras un poco, sería más fácil imaginar lo que quieres hacer.
Suma
2
Sé que esto no responde a la pregunta que hizo, pero parece que estaba buscando para ver si la barra de navegación estaba oculta o no. Si es así, podría haber utilizado self.navigationController.navigationBarHidden Esperanza totalmente esto ayude a alguien :)
taylorcressy
2
En iOS 7+, es posible que también deba considerar la barra de estado de 20px según su aplicación
Slayter,
94

Con iPhone-X, la altura de la barra superior (barra de navegación + barra de estado) cambia (aumenta).

Pruebe esto si desea la altura exacta de la barra superior (tanto la barra de navegación como la barra de estado):

ACTUALIZAR

iOS 13

Como statusBarFramefue desaprobado en iOS13puede usar esto:

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

C objetivo

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)

Para mayor facilidad, pruebe esta extensión 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
fuente
3
La respuesta Swift 4 me devuelve una altura 0.
Chewie The Chorkie
61

Versión rápida :

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
Rey Mago
fuente
Siempre devuelve 44. ¿Cómo saber el tamaño contraído (44) o el tamaño expandido (títulos grandes) ??? Dinámicamente, por supuesto. (Sé lo que mide)
Markus
6

¿Intentaste esto?

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

Admite iOS 13 y a continuación:

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
fuente
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 );
*/

Entonces todo lo que realmente necesitamos es

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ç
fuente
2

Mi aplicación tiene un par de vistas que requieren una barra de navegación personalizada en la interfaz de usuario para la apariencia, sin embargo, sin controlador de navegación. Y se requiere que la aplicación sea compatible con la versión de iOS anterior a iOS 11, por lo que no se pudo utilizar la práctica guía de diseño de área segura, y tengo que ajustar la posición y la altura de la barra de navegación mediante programación.

Adjunté la barra de navegación a su supervista directamente, omitiendo la guía de diseño del área segura como se mencionó anteriormente. Y la altura de la barra de estado podría recuperarse fácilmente de la aplicación UIA, pero la altura predeterminada de la barra de navegación es realmente una molestia ...

Me llamó la atención durante casi media noche, con una serie de búsquedas y pruebas, hasta que finalmente recibí la pista de otra publicación (aunque no me funcionó), de que realmente podías obtener la altura de UIView.sizeThatFits (), así :

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

    [super viewWillLayoutSubviews];    
}

Finalmente, una barra de navegación perfecta que se ve exactamente igual a la integrada.

Stephen Liu
fuente
2

Si solo quieres obtener la navigationBaraltura, es simple:

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

Sin embargo, si necesita la altura de la muesca superior del iPhone, no necesita obtener la navigationBaraltura y agregarle la statusBaraltura, simplemente puede llamar safeAreaInsetspor eso existe.

self.view.safeAreaInsets.top
mojtaba al moussawi
fuente
1

La bombilla comenzó a encenderse. Desafortunadamente, no he descubierto una forma uniforme de corregir el problema, como se describe a continuación.

Creo que todo mi problema se centra en mis autoresizingMasks. Y la razón por la que he concluido es que existen los mismos síntomas, con o sin UIWebView. Y ese síntoma es que todo es color de rosa para Portrait. Para Landscape, el UIButton más inferior aparece detrás de TabBar.

Por ejemplo, en una UIView, tengo, de arriba a abajo:

UIView : ambos resortes establecidos (caso predeterminado) y sin puntales

UIScrollView : si configuro los dos resortes y borro todo lo demás (como el UIView), el UIButton se entromete en el objeto que se encuentra inmediatamente encima de él. Si borro todo, UIButton está bien, pero las cosas en la parte superior se esconden detrás de la barra de estado. Configurando solo el puntal superior, el UIButton aparece detrás de la barra de pestañas.

UILabel y UIImage son los siguientes verticalmente: conjunto de puntal superior, flexible en cualquier otro lugar

Solo para completar la imagen para los pocos que tienen un UIWebView:

UIWebView - Struts: arriba, izquierda, derecha Resortes: ambos

UIButton : nada configurado, es decir, flexible en todas partes

Aunque mi bombilla es tenue, parece haber esperanza.


fuente
Establezca el puntal superior y configure los dos resortes de UIWebView: problema resuelto y agradece los racimos. De hecho, mi único problema restante es diseñar esos gráficos malditos @ 2X, etc. Utilizo GraphicConverter de una manera muy simple y funciona muy bien para el diseño de páginas web. Pero todas estas cosas de 30px, 57px: al menos voy a entrar en territorio desconocido para mí.
1

Aquí está el comienzo de mi respuesta a su actualización:

¿Por qué la altura del contenido de mi UIWebView no cambia con la rotación?

¿Podría ser eso porque su cambio de tamaño automático no tiene la máscara de autoresizing para todas las direcciones?

Otra sugerencia antes de volver para esto, podría utilizar una barra de herramientas para sus necesidades. Es un poco más simple, siempre estará en la parte inferior, rota / coloca automáticamente. Puede ocultarlo / mostrarlo a voluntad, etc. Algo así: http://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg

Es posible que hayas visto esa opción, pero solo la arrojaste.

Otra idea, ¿podría detectar de qué orientación está rotando y simplemente colocar el botón mediante programación para ajustar la barra de pestañas? (Esto es posible con código)

Suma
fuente
Después de aproximadamente 2 semanas para abordar esto, decidí que el "problema" se hizo más difícil al colocar un UIButton DEBAJO de la subvista UIWebView. Entonces, puse el botón ARRIBA. Francamente, simplemente no se ve "correcto" de esa manera ... pero ahora funciona SORT OF. ABAJO o ARRIBA, UIWebView ha establecido el puntal superior y solo el resorte horizontal. Por cierto, es el contentHeight de UIWebView que no cambia con la rotación.
0

He usado:

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

Funciona muy bien si desea obtener la altura de la barra de navegación Y su origen Y.

usuario3332228
fuente
0

Swift 5

Si quieres o considera también el safeArea:

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

Extensión Handy Swift 4, en caso de que sea útil para otra persona. Funciona incluso si el controlador de vista actual no muestra una barra de navegación.

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

Uso:

UINavigationController.navBarHeight()
Nombre claveDuquesa
fuente