Programowo pobierz wysokość paska nawigacji

133

Wiem, że obecność kontrolera widoku more (paska nawigacji) powoduje obniżenie UIView o jego wysokość. Wiem też, że ta wysokość = 44px. Odkryłem również, że to wciśnięcie utrzymuje [self.view].frame.origin.y = 0.

Jak więc określić wysokość tego paska nawigacji, inaczej niż tylko ustawiając go na stałą?

Lub, w przypadku krótszej wersji, jak ustalić, czy mój UIView jest wyświetlany z paskiem nawigacyjnym u góry?


Żarówka zaczęła się zapalać. Niestety nie znalazłem jednolitego sposobu rozwiązania problemu, jak opisano poniżej.

Uważam, że cały mój problem koncentruje się na moich automatycznych maskach. I powód, dla którego doszedłem do wniosku, że istnieją te same symptomy, z UIWebView lub bez niego. A symptomem tego jest to, że w przypadku Portretu wszystko jest brzoskwiniowe. W przypadku krajobrazu, najniżej położony UIButton pojawia się za TabBar.

Na przykład na jednym UIView mam, od góry do dołu:

UIView - zestaw obu sprężyn (przypadek domyślny) i brak rozpórek

UIScrollView - jeśli ustawię dwie sprężyny i wyczyszczę wszystko inne (jak UIView), wówczas UIButton wkracza na obiekt bezpośrednio nad nim. Jeśli wyczyszczę wszystko, to UIButton jest OK, ale rzeczy na samej górze chowają się za StatusBar Ustawiając tylko górną rozpórkę, UIButton wyskakuje za Tab Bar.

UILabel i UIImage obok w pionie - zestaw górnych rozpórek, elastyczny wszędzie indziej

Aby uzupełnić obraz dla nielicznych, którzy mają UIWebView:

UIWebView - Rozpórki: górna, lewa, prawa Sprężyny: obie

UIButton - nic nie jest ustawione, czyli wszędzie jest elastyczny

Chociaż moja żarówka jest przygaszona, wydaje się, że jest nadzieja.


Proszę o wyrozumiałość, ponieważ potrzebowałem więcej miejsca niż przewidziano na krótką odpowiedź na komentarz.

Dziękuję za próbę zrozumienia, na co tak naprawdę łowię ... więc proszę bardzo.

1) Każdy UIViewController (aplikacja TabBar) ma UIImage, jakiś tekst i cokolwiek na górze. Innym wspólnym mianownikiem jest przycisk UIB na dole. W przypadku niektórych UIViewControllers mam UIWebView powyżej UIButton.

A więc UIImage, tekst itp. UIWebView (na SOME) UIButton

Otaczający wszystko powyższe jest UIScrollView.

2) Dla tych, którzy mają UIWebView, jego autoresizeMask wygląda następująco:

   
   |
   —

   ^
   |
   |

| - | ← ---- → | - | | | V Maska UIButton nie ma nic ustawionego, tzn. Jest wszędzie elastyczna

W ramach my -viewDidLoad wywołuję moje -repositionSubViews, w ramach których wykonuję następujące czynności:

Jeśli nie ma UIWebView, nie robię nic poza wyśrodkowaniem UIButton, który umieściłem w IB.

Jeśli mam UIWebView, określam jego * zawartość * wysokość i ustawiam ramkę tak, aby obejmowała całą zawartość.

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

Kiedy to zrobię, programowo wciskam przycisk UIButton w dół, aby znalazł się poniżej UIWebView.

Wszystko działa, dopóki nie obrócę go z portretu na krajobraz.

Wywołuję moje -repositionSubViews w ramach mojego -didRotateFromInterfaceOrientation.

Dlaczego wysokość zawartości mojego UIWebView nie zmienia się wraz z obrotem?

Od pionowej do poziomej szerokość treści powinna się zwiększyć, a wysokość powinna się zmniejszyć. Robi wizualnie tak, jak powinien, ale nie według mojego NSLog.

W każdym razie, z lub bez UIWebView, przycisk, o którym mówiłem, przesuwa się poniżej paska TabBar w trybie poziomym, ale nie przewija się w górę, aby go zobaczyć. Widzę go za TabBarem, kiedy „energicznie” przewijam, ale potem „cofa się” za TabBar.

Podsumowując, to ostatnie jest powodem, dla którego zapytałem o wysokość TabBar i NavigationBar, ponieważ TabBar umieszcza się na dole UIView, a NavigationBar wypycha UIView w dół.

Teraz dodam tutaj komentarz lub dwa, ponieważ wcześniej nie miałyby one sensu.

Bez UIWebView zostawiam wszystko tak, jak widzi IB.

Za pomocą UIWebView zwiększam frame.height UIWebView do jego contentHeight, a także dostosowuję w górę wysokość otaczającego widoku UIScrollView, który otacza wszystkie widoki podrzędne.

Cóż, masz to.

Krunal
źródło

Odpowiedzi:

262

Zrobić coś takiego?

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

Wersja swift znajduje się tutaj


AKTUALIZACJA

iOS 13

Ponieważ statusBarFramezostała wycofana w iOS13, możesz użyć tego:

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
źródło
Dziękuję dziękuję. ALE, teraz, gdy rozwiązałeś ten problem, po prostu w jaki sposób mogę określić, czy NavigationController, znany również jako MoreViewController, jest wyświetlany dla mojej aplikacji paska kart.
Nie do końca rozumiem, co próbujesz powiedzieć. Czy próbujesz dowiedzieć się, czy wyświetla się MoreViewController? (Jeśli tak, co chcesz zrobić?), A jeśli nie, czy możesz wyjaśnić, co dokładnie masz na myśli?
Suma
Ponownie przeczytałem twoje pytanie i nadal nie rozumiem, co chcesz zrobić? Jeśli chcesz coś zrobić, gdy pojawi się widok, powinieneś wstawić kod do viewDidAppear. Jeśli trochę wyjaśnisz, łatwiej będzie ci zorientować się, co chcesz zrobić.
Suma
2
Wiem, że to nie odpowiada na zadane przez niego pytanie, ale wygląda na to, że szukał, czy pasek nawigacji jest ukryty, czy nie. Jeśli tak, mógł użyć self.navigationController.navigationBarHidden Hope w pełni to komuś pomaga :)
taylorcressy
2
W systemie iOS 7+ może być konieczne uwzględnienie paska stanu o wielkości 20 pikseli, w zależności od aplikacji
Slayter
95

W przypadku iPhone'a-X wysokość górnego paska (pasek nawigacji + pasek stanu) jest zmieniona (zwiększona).

Spróbuj tego, jeśli chcesz uzyskać dokładną wysokość górnego paska (zarówno pasek nawigacji + pasek stanu):

AKTUALIZACJA

iOS 13

Ponieważ statusBarFramezostała wycofana w iOS13, możesz użyć tego:

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

Cel C

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

Szybki 4

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

Dla ułatwienia wypróbuj to rozszerzenie 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)
    }
}

Szybki 3

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

Krunal
źródło
3
Odpowiedź języka Swift 4 zwraca dla mnie wysokość 0.
Chewie The Chorkie
61

Wersja Swift :

let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
King-Wizard
źródło
Zawsze zwraca 44. Po czym poznać rozmiar zwinięty (44) lub rozwinięty (duże tytuły) ??? Oczywiście dynamicznie. (Wiem, co mierzy)
Markus
6

Próbowałeś tego?

let barHeight = self.navigationController?.navigationBar.frame.height ?? 0
Keaz
źródło
5

Obsługa iOS 13 i poniżej:

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
źródło
dla mnie view.window jest zerowe. Więc muszę pobrać ramkę z UIApplication.shared.windowskeywnidow. (iOS 14)
Lal Krishna
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 );
*/

Więc jedyne, czego potrzebujemy, to

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ç
źródło
2

Moja aplikacja ma kilka widoków, które wymagały dostosowania paska nawigacji w interfejsie użytkownika, aby wyglądać i działać, jednak bez kontrolera nawigacyjnego. A aplikacja jest wymagana do obsługi wersji iOS wcześniejszej niż iOS 11, więc nie można było korzystać z podręcznego przewodnika po bezpiecznym obszarze i muszę programowo dostosować pozycję i wysokość paska nawigacji.

Podłączyłem pasek nawigacji bezpośrednio do jego nadzoru, pomijając przewodnik po układzie bezpiecznego obszaru, jak wspomniano powyżej. Wysokość paska stanu można łatwo pobrać z UIApplication, ale domyślna wysokość paska nawigacji jest naprawdę uciążliwa ...

Uderzyło mnie przez prawie pół nocy, z wieloma poszukiwaniami i testami, aż w końcu dostałem wskazówkę z innego postu (choć nie działającego dla mnie), że tak naprawdę możesz uzyskać wysokość z UIView.sizeThatFits (), w ten sposób :

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

    [super viewWillLayoutSubviews];    
}

Wreszcie, doskonały pasek nawigacyjny wyglądający dokładnie tak samo jak wbudowany!

Stephen Liu
źródło
2

Jeśli chcesz uzyskać navigationBartylko wysokość, jest to proste:

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

Jeśli jednak potrzebujesz wysokości górnej krawędzi iPhone'a, nie musisz pobierać navigationBarwysokości i dodawać do niej statusBarwysokości, możesz po prostu nazwać safeAreaInsetsto, dlaczego istnieje.

self.view.safeAreaInsets.top
mojtaba al moussawi
źródło
2

Szybki 5

Jeśli chcesz o rozważyć również safeArea:

 let height = navigationController?.navigationBar.frame.maxY  
Kivia Martins Brito
źródło
1

Żarówka zaczęła się zapalać. Niestety nie znalazłem jednolitego sposobu rozwiązania problemu, jak opisano poniżej.

Uważam, że cały mój problem koncentruje się na moich automatycznych maskach. I powód, dla którego doszedłem do wniosku, że istnieją te same symptomy, z UIWebView lub bez niego. A symptomem tego jest to, że w przypadku Portretu wszystko jest brzoskwiniowe. W przypadku krajobrazu, najniżej położony UIButton pojawia się za TabBar.

Na przykład na jednym UIView mam, od góry do dołu:

UIView - zestaw obu sprężyn (przypadek domyślny) i brak rozpórek

UIScrollView - Jeśli ustawię dwie sprężyny i wyczyszczę wszystko inne (jak UIView), wówczas UIButton wkracza na obiekt bezpośrednio nad nim. Jeśli wszystko wyczyszczę, to UIButton jest OK, ale rzeczy na samej górze chowają się za StatusBar Ustawiając tylko górną rozpórkę, UIButton wyskakuje za paskiem Tab.

UILabel i UIImage obok w pionie - zestaw górnych rozpórek, elastyczny wszędzie indziej

Aby uzupełnić obraz dla nielicznych, którzy mają UIWebView:

UIWebView - Rozpórki: górna, lewa, prawa Sprężyny: obie

UIButton - nic nie jest ustawione, czyli wszędzie jest elastyczny

Chociaż moja żarówka jest przygaszona, wydaje się, że jest nadzieja.


źródło
Ustaw górną rozpórkę i ustaw dwie sprężyny UIWebView - problem rozwiązany i paczki dzięki. Właściwie jedynym moim problemem jest zaprojektowanie tych przeklętych @ 2X itp. Grafiki. Używam GraphicConvertera w bardzo prosty sposób i bardzo dobrze sprawdza się przy projektowaniu stron WWW. Ale wszystkie te 30px, 57px rzeczy - przynajmniej dla mnie wkraczam w nieznane terytorium.
1

Oto początek mojej odpowiedzi na Twoją aktualizację:

Dlaczego wysokość zawartości mojego UIWebView nie zmienia się wraz z obrotem?

Czy to możliwe, ponieważ twoja automatyczna zmiana rozmiaru nie ma automatycznej maski zmiany rozmiaru dla wszystkich kierunków?

Jeszcze jedna sugestia, zanim wrócę po to, czy mógłbyś użyć paska narzędzi do swoich potrzeb. To trochę prostsze, zawsze będzie na dole, auto-rotacje / pozycje. Możesz to ukryć / pokazać do woli itp. Coś takiego: http://cdn.artoftheiphone.com/wp-content/uploads/2009/01/yellow-pages-iphone-app-2.jpg

Być może spojrzałeś na tę opcję, ale po prostu ją wyrzucił.

Inny pomysł, czy mógłbyś wykryć, z jakiej orientacji się obracasz, i po prostu programowo umieścić przycisk, aby dostosować się do paska kart. (Jest to możliwe za pomocą kodu)

Suma
źródło
Po około 2 tygodniach rozwiązywania tego problemu zdecydowałem, że „problem” stał się trudniejszy przez umieszczenie przycisku UIBUTTON PONIŻEJ widoku podrzędnego UIWebView. Więc umieściłem przycisk POWYŻEJ. Szczerze mówiąc, po prostu nie wygląda to "dobrze" w ten sposób ... ale teraz działa RÓŻNIE. PONIŻEJ lub POWYŻEJ UIWebView ustawił górną rozpórkę i tylko poziomą sprężynę. BTW, jego contentHeight z UIWebView, który nie zmienia się wraz z obrotem.
0

Używałem:

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

Działa świetnie, jeśli chcesz uzyskać wysokość paska nawigacji ORAZ jego początek Y.

user3332228
źródło
0

Handy Swift 4 rozszerzenie, na wypadek gdyby było pomocne dla kogoś innego. Działa, nawet jeśli bieżący kontroler widoku nie wyświetla paska nawigacji.

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

Stosowanie:

UINavigationController.navBarHeight()
Kryptonim Księżna
źródło
0

iOS 14

Dla mnie view.windowma wartość NULL na iOS 14.

extension UIViewController {
    var topBarHeight: CGFloat {
        var top = self.navigationController?.navigationBar.frame.height ?? 0.0
        if #available(iOS 13.0, *) {
            top += UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
        } else {
            top += UIApplication.shared.statusBarFrame.height
        }
        return top
    }
}
Lal Krishna
źródło