A livello di codice ottenere altezza della barra di navigazione


131

So che la presenza di più controller di visualizzazione (barra di navigazione) spinge l'UIView per altezza. So anche che questa altezza = 44px. Ho anche scoperto che questo push down mantiene il [self.view].frame.origin.y = 0.

Quindi, come faccio a determinare l'altezza di questa barra di navigazione, oltre a impostarla su una costante?

Oppure, versione più breve, come posso determinare se il mio UIView viene visualizzato con la barra di navigazione in alto?


La lampadina ha iniziato ad accendersi. Sfortunatamente, non ho scoperto un modo uniforme per correggere il problema, come descritto di seguito.

Credo che tutto il mio problema sia incentrato sui miei autoresizingMasks. E il motivo per cui ho concluso che esistono gli stessi sintomi, con o senza UIWebView. E quel sintomo è che tutto è perfetto per Portrait. Per Orizzontale, il pulsante UIB più in basso si apre dietro la TabBar.

Ad esempio, su un UIView, ho, dall'alto verso il basso:

Vista UIV - entrambe le molle impostate (caso predefinito) e nessun puntone

UIScrollView - Se imposto le due molle e pulisco tutto il resto (come l'UIView), il pulsante UIB si intromette nell'oggetto immediatamente sopra di esso. Se elimino tutto, UIButton è OK, ma le cose in cima si nascondono dietro la StatusBar Impostando solo il montante superiore, l'UIButton si apre dietro la barra delle schede.

UILabel e UIImage si avvicinano verticalmente: set di montanti superiori, flessibile ovunque

Solo per completare l'immagine per i pochi che hanno un UIWebView:

UIWebView - Puntoni: in alto, a sinistra, a destra Molle: entrambe

UIButton: niente di fisso, cioè flessibile ovunque

Sebbene la mia lampadina sia fioca, sembra esserci speranza.


Ti prego, abbi pazienza perché avevo bisogno di più spazio di quello previsto per un breve commento di risposta.

Grazie per aver cercato di capire cosa sto veramente pescando ... quindi ecco qui.

1) Ogni UIViewController (un'app TabBar) ha un UIImage, del testo e quant'altro in cima. Un altro comune denominatore è un UIButton in basso. Su alcuni UIViewController ho un UIWebView sopra l'UIButton.

Quindi, UIImage, testo ecc. UIWebView (su ALCUNI) UIButton

Che circonda tutto quanto sopra è un UIScrollView.

2) Per quelli che hanno un UIWebView, la sua maschera di ridimensionamento automatico è simile a:

   
   |
   

   ^
   |
   |

| - | ← ---- → | - | | | V La maschera di UIButton non ha nulla da impostare, cioè flessibile ovunque

All'interno di my -viewDidLoad, chiamo my -repositionSubViews in cui eseguo le seguenti operazioni:

Se non c'è UIWebView, non faccio altro che centrare il pulsante UIB che ho inserito con IB.

Se ho un UIWebView, allora ne determina l'altezza * contenuto * e imposto la cornice per racchiudere l'intero contenuto.

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

Una volta che lo faccio, spingo programmaticamente il pulsante UIB verso il basso in modo che finisca posizionato sotto UIWebView.

Tutto funziona, fino a quando non lo giro da Ritratto a Paesaggio.

Chiamo my -repositionSubViews all'interno di -didRotateFromInterfaceOrientation.

Perché l'altezza del contenuto di UIWebView non cambia con la rotazione?

Da Verticale a Orizzontale, la larghezza del contenuto dovrebbe espandersi e l'altezza del contenuto dovrebbe ridursi. Lo fa visivamente come dovrebbe, ma non secondo il mio NSLog.

Ad ogni modo, con o senza UIWebView, il pulsante di cui ho parlato si sposta sotto la Tabbar in modalità orizzontale ma non scorrerà verso l'alto per essere visto. Lo vedo dietro il Tabbar quando scorro "vigorosamente", ma poi "ricade" dietro il Tabbar.

In conclusione, quest'ultima è la ragione per cui ho chiesto l'altezza del TabBar e del NavigationBar perché il TabBar si posiziona nella parte inferiore dell'UIView e il NavigationBar spinge l'UIView verso il basso.

Ora aggiungerò un commento o due qui perché non avrebbero avuto senso prima.

Senza UIWebView, lascio tutto come visto da IB.

Con un UIWebView, ingrandisco il frame di UIWebView.Altezza al suo contenutoAltezza e regola anche verso l'alto l'altezza del UIScrollView circostante che circonda tutte le viste secondarie.

Beh, il gioco è fatto.

Risposte:


258

Fare qualcosa del genere?

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

La versione rapida si trova qui


AGGIORNARE

iOS 13

Dato che è statusBarFramestato deprecato iOS13puoi usare questo:

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

Grazie grazie. MA, ora che hai risolto quel problema, come faccio a determinare se NavigationController, noto anche come MoreViewController, viene visualizzato per la mia app della barra delle schede.

Non capisco esattamente cosa stai cercando di dire. Stai cercando di capire se MoreViewController sta mostrando? (In tal caso, cosa vuoi fare?) E se no, potresti chiarire cosa intendi esattamente?
Somma

Ho letto di nuovo la tua domanda e non ho ancora capito cosa vuoi fare? Se vuoi fare qualcosa quando appare la vista, devi inserire il codice in viewDidAppear. Se chiarisci un po ', renderebbe più facile capire cosa vuoi fare.
Somma il

2
So che questo non affronta la domanda che ha posto, ma sembra che stesse cercando di vedere se la barra di navigazione era nascosta o meno. Se è così, avrebbe potuto usare self.navigationController.navigationBarHidden Hope pienamente questo aiuta qualcuno :)
taylorcressy

2
In iOS 7+ potresti dover considerare anche la barra di stato 20px a seconda della tua applicazione
Slayter

94

Con iPhone-X, l'altezza della barra superiore (barra di navigazione + barra di stato) viene modificata (aumentata).

Prova questo se vuoi l'altezza esatta della barra superiore (sia barra di navigazione + barra di stato):

AGGIORNARE

iOS 13

Dato che è statusBarFramestato deprecato iOS13puoi usare questo:

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

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

Per facilità, prova questa estensione 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)


3
La risposta di Swift 4 mi restituisce un'altezza di 0.
Chewie The Chorkie,

61

Versione rapida :

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height

Restituisce sempre 44. Come sapere la dimensione compressa (44) o la dimensione espansa (titoli di grandi dimensioni) ??? Dinamicamente, ovviamente. (So ​​cosa misura)
Markus

6

Hai provato questo?

let barHeight = self.navigationController?.navigationBar.frame.height ?? 0

5

Supporta iOS 13 e versioni precedenti:

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

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

Quindi tutto ciò di cui abbiamo effettivamente bisogno è

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;

2

La mia applicazione ha un paio di visualizzazioni che richiedono una barra di navigazione personalizzata nell'interfaccia utente per l'aspetto grafico, tuttavia senza controller di navigazione. E l'applicazione è richiesta per supportare la versione iOS precedente a iOS 11, quindi non è stato possibile utilizzare la pratica guida al layout dell'area sicura e devo regolare la posizione e l'altezza della barra di navigazione a livello di codice.

Ho attaccato direttamente la barra di navigazione alla sua superview, saltando la guida al layout dell'area sicura come menzionato sopra. E l'altezza della barra di stato potrebbe essere facilmente recuperata da UIApplication, ma l'altezza della barra di navigazione predefinita è davvero un dolore ...

Mi ha colpito per quasi mezza notte, con una serie di ricerche e test, fino a quando finalmente ho ricevuto il suggerimento da un altro post (non funzionante per me), che potresti effettivamente ottenere l'altezza da UIView.sizeThatFits (), in questo modo :

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

    [super viewWillLayoutSubviews];    
}

Finalmente una barra di navigazione perfetta che sembra esattamente la stessa di quella integrata!


2

Se vuoi ottenere navigationBarsolo l' altezza, è semplice:

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

Tuttavia, se hai bisogno dell'altezza di prim'ordine di iPhone non hai bisogno di ottenere l' navigationBaraltezza e aggiungere ad essa l' statusBaraltezza, puoi semplicemente chiamare safeAreaInsetsquesto è il motivo per cui esistono.

self.view.safeAreaInsets.top

1

La lampadina ha iniziato ad accendersi. Sfortunatamente, non ho scoperto un modo uniforme per correggere il problema, come descritto di seguito.

Credo che tutto il mio problema sia incentrato sui miei autoresizingMasks. E il motivo per cui ho concluso che esistono gli stessi sintomi, con o senza UIWebView. E quel sintomo è che tutto è perfetto per Portrait. Per Orizzontale, il pulsante UIB più in basso si apre dietro la TabBar.

Ad esempio, su un UIView, ho, dall'alto verso il basso:

Vista UIV - entrambe le molle impostate (caso predefinito) e nessun puntone

UIScrollView - Se imposto le due molle e pulisco tutto il resto (come l'UIView), il pulsante UIB si intromette sull'oggetto immediatamente sopra di esso. Se cancello tutto, UIButton va bene, ma le cose in cima si nascondono dietro la StatusBar Impostando solo il montante superiore, l'UIButton si apre dietro la barra delle schede.

UILabel e UIImage si avvicinano verticalmente: set di montanti superiori, flessibile ovunque

Solo per completare l'immagine per i pochi che hanno un UIWebView:

UIWebView - Puntoni : in alto, a sinistra, a destra Molle: entrambe

UIButton : niente di fisso , cioè flessibile ovunque

Sebbene la mia lampadina sia fioca, sembra esserci speranza.


Posiziona il montante superiore e imposta le due molle di UIWebView - problema risolto e grazie a mazzi. È un dato di fatto, il mio unico problema rimasto è progettare quelle grafiche maledette @ 2X, ecc. Uso GraphicConverter in un modo molto semplice e funziona molto bene per la progettazione di pagine Web. Ma tutte queste cose da 30px, 57px - almeno vado in un territorio inesplorato.

1

Ecco l'inizio della mia risposta al tuo aggiornamento:

Perché l'altezza del contenuto di UIWebView non cambia con la rotazione?

Potrebbe essere perché il tuo ridimensionamento automatico non ha la maschera di ridimensionamento automatico per tutte le direzioni?

Un altro suggerimento prima di tornare per questo, potresti usare una barra degli strumenti per le tue esigenze. È un po 'più semplice, sarà sempre sul fondo, ruota automaticamente / posiziona. Puoi nasconderlo / mostrarlo a piacimento, ecc. In questo modo: http://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg

Potresti aver preso in considerazione quell'opzione, ma semplicemente lanciandola là fuori.

Un'altra idea, potresti forse rilevare da quale orientamento stai ruotando e posizionare semplicemente il pulsante a livello di codice per regolare la barra delle schede. (Questo è possibile con il codice)


Dopo circa 2 settimane su come affrontare questo, ho deciso che il "problema" è stato reso più difficile inserendo un UIButton SOTTO la sotto-vista UIWebView. Quindi, ho messo il pulsante SOPRA. Francamente, non sembra "giusto" in quel modo ... ma ora funziona SORT. SOTTO o SOPRA UIWebView ha impostato il montante superiore e solo la molla orizzontale. A proposito, è il contenuto Altezza di UIWebView che non cambia con la rotazione.

0

Ho usato:

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

Funziona alla grande se vuoi ottenere l'altezza della barra di navigazione E la sua origine a Y.


0

Swift 5

Se vuoi o considera anche safeArea:

 let height = navigationController?.navigationBar.frame.maxY  

0

Estensione Handy Swift 4, nel caso sia utile a qualcun altro. Funziona anche se il controller di visualizzazione corrente non visualizza una barra di navigazione.

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()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.