iPhone ukryj pasek nawigacji tylko na pierwszej stronie

381

Mam poniżej kod, który ukrywa i pokazuje pasek nawigacyjny. Jest ukryty, gdy ładuje się pierwszy widok, a następnie jest ukryty, gdy wywoływane są „dzieci”. Problem w tym, że nie mogę znaleźć zdarzenia / akcji, która spowodowałaby jego ponowne ukrycie po powrocie do widoku głównego ...

Mam przycisk „test” na stronie głównej, który ręcznie wykonuje akcję, ale nie jest ładny i chcę, aby był automatyczny.

-(void)hideBar 
{
    self.navController.navigationBarHidden = YES;
}
-(void)showBar 
{       
    self.navController.navigationBarHidden = NO;
}
Lee Armstrong
źródło

Odpowiedzi:

1035

Najlepszym rozwiązaniem, jakie znalazłem, jest wykonanie następujących czynności w pierwszym kontrolerze widoku .

Cel C

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:NO animated:animated];
    [super viewWillDisappear:animated];
}

Szybki

override func viewWillAppear(animated: Bool) {
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
    super.viewWillAppear(animated)
}

override func viewWillDisappear(animated: Bool) {
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
    super.viewWillDisappear(animated)
} 

Spowoduje to animację paska nawigacyjnego od lewej (wraz z następnym widokiem) po naciśnięciu następnego UIViewControllerna stosie i animację od lewej (wraz ze starym widokiem) po naciśnięciu przycisku Wstecz na UINavigationBar.

Należy również pamiętać, że nie są to metody delegowania, zastępujesz UIViewControllerimplementację tych metod i zgodnie z dokumentacją musisz wywołać implementację super w jakimś miejscu .

Alan Rogers
źródło
2
To totalnie kołysze! Walczyłem z tym przez co najmniej jeden dzień. Dzięki!!!
James Testa
26
OSTRZEŻENIE: Stwarza to bardzo zły błąd podczas wykonywania szybkiego czyszczenia wstecznego. Załóżmy, że A (bez paska nawigacyjnego) i B (z paskiem nawigacyjnym) wepchnięte na stos. W widoku B i szybkim czyszczeniu wstecz, ale zwolnij wystarczająco wcześnie, aby pozostać na B, pasek nawigacyjny nadal jest ukryty. Teraz nie ma już możliwości powrotu. Wynika to z animated=YES. Wiem, że wygląda brzydko animated=NO, ale wydaje się, że gdy animacja ukrywania paska nawigacyjnego nie jest jeszcze ukończona, to animacja pokazująca ją ponownie jest ignorowana. Nie ma jeszcze rozwiązania.
fabb
3
W Swift: zastąpienie widoku funWillAppear (animowane: Bool) {self.navigationController? .SetNavigationBarHidden (true, animated: true) super.viewWillAppear (true)} zastąpienie func viewWillDisappear (animowane: Bool) {self.navigationController? .SetNavigationBarHidden animowane: false) super.viewWillDisappear (true)}
Kitson
7
Odpowiedź na pytanie padła w 2010 roku i pomaga mi pod koniec 2015 roku! Dziękuję Ci.
oyalhi,
1
To właśnie nazywam legendarną odpowiedzią. Znakomity sztuczka. Nawet działający po dziesięcioleciach ... Zaimplementował to samo szybko, działając bezbłędnie. +1 za twoją odpowiedź @Alan Rogers
onCompletion
62

Innym podejściem, które znalazłem, jest ustawienie delegata dla NavigationController:

navigationController.delegate = self;

i użyj setNavigationBarHiddenwnavigationController:willShowViewController:animated:

- (void)navigationController:(UINavigationController *)navigationController 
      willShowViewController:(UIViewController *)viewController 
                    animated:(BOOL)animated 
{   
    // Hide the nav bar if going home.
    BOOL hide = viewController != homeViewController;
    [navigationController setNavigationBarHidden:hide animated:animated];
}

Łatwy sposób na dostosowanie zachowania każdego z nich ViewControllerw jednym miejscu.

Czad M.
źródło
Kiedy zostanie to wywołane?
Zalak Patel
1
Idealne rozwiązanie. To powinna być zaakceptowana odpowiedź. Dzięki!
Samah
Idealna odpowiedź. Działa również w przypadku, gdy nie możemy przesłonić metod viewWillAppear i viewWillDisappear na pierwszym kontrolerze widoku.
pjuzeliunas
1
Niesamowite. Wybrana odpowiedź działa dobrze, jednak tylko w prostych aplikacjach. Ta odpowiedź działa, gdy pasek nawigacyjny znajduje się w kontrolerze kart i wypycha / prezentuje różne VC na różne sposoby.
Jonathan Winger-Lang
To najlepsza odpowiedź. Najlepszą odpowiedzią może być błąd jako opis @ fabb .
Ryan.Yuen,
18

Jednym drobnym drobiazgiem, który musiałem wprowadzić w innych odpowiedziach, jest jedynie odsłonięcie paska w widoku. Zniknie, jeśli przyczyną jego zniknięcia jest wciśnięcie na niego elementu nawigacyjnego. Jest tak, ponieważ widok może zniknąć z innych powodów.

Odsłoniłem pasek tylko wtedy, gdy ten widok nie jest już najwyższym widokiem:

- (void) viewWillDisappear:(BOOL)animated
{
    if (self.navigationController.topViewController != self)
    {
        [self.navigationController setNavigationBarHidden:NO animated:animated];
    }

    [super viewWillDisappear:animated];
}

źródło
3
+1, zwykle nie chcesz pokazywać paska nawigacyjnego podczas naciskania modalnego okna dialogowego.
João Portela,
17

Umieściłbym kod w widoku delegata viewWillAppear na każdym wyświetlanym widoku:

W ten sposób musisz go ukryć:

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject hideBar];
}

W ten sposób musisz to pokazać:

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject showBar];
}
Pablo Santa Cruz
źródło
Lee, jeśli to rozwiązało twój problem, zaznacz Pablo jako odpowiedź „rozwiązania”.
Rog
2
Jedynym problemem jest to, że pasek nawigacyjny „wyskakuje” i wyświetla się podczas przechodzenia od jednego widoku do drugiego. Czy jest możliwe, aby pasek nawigacji nie pojawiał się w pierwszym widoku, a kiedy drugi widok wsunie się na swoje miejsce, ma pasek nawigacji, bez żadnego wyskakiwania?
Henning
2
@henning Aby NavBar wsuwał / wysuwał się zgodnie z oczekiwaniami, musisz użyć setNavigationBarHidden: animated :. Zobacz odpowiedź Alana Rogersa poniżej (która naprawdę powinna być oznaczona jako „rozwiązanie”).
Nick Forge
2
Ta odpowiedź jest nieco błędna (viewWill / DidAppear) powinna wywoływać super. Zobacz także moją odpowiedź poniżej, aby znaleźć rozwiązanie, w którym nie musisz dodawać jej do KAŻDEGO kontrolera widoku.
Alan Rogers
15

Aktualnie akceptowana odpowiedź nie pasuje do zamierzonego zachowania opisanego w pytaniu. Pytanie wymaga, aby pasek nawigacji był ukryty w kontrolerze widoku głównego, ale widoczny wszędzie indziej, ale zaakceptowana odpowiedź ukrywa pasek nawigacji w określonym kontrolerze widoku. Co się stanie, gdy inna instancja pierwszego kontrolera widoku zostanie wypchnięta na stos? Ukryje pasek nawigacji, mimo że nie patrzymy na kontroler widoku głównego.

Zamiast tego strategia korzystania z @Chad M. UINavigationControllerDelegatejest dobra, a tutaj jest bardziej kompletne rozwiązanie. Kroki:

  1. Podklasa UINavigationController
  2. Zaimplementuj -navigationController:willShowViewController:animatedmetodę pokazywania lub ukrywania paska nawigacji w zależności od tego, czy pokazuje kontroler widoku głównego
  3. Zastąp metody inicjowania, aby ustawić podklasę UINavigationController jako własną delegację

Pełny kod dla tego rozwiązania można znaleźć w tej Gist . Oto navigationController:willShowViewController:animatedimplementacja:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    /* Hide navigation bar if root controller */
    if ([viewController isEqual:[self.viewControllers firstObject]]) {
        [self setNavigationBarHidden:YES animated:animated];
    } else {
        [self setNavigationBarHidden:NO animated:animated];
    }
}
hunteros
źródło
2
To jest bardziej odpowiednia odpowiedź niż zaakceptowana
Pavel Gurov
14

w Swift 3:

override func viewWillAppear(_ animated: Bool) {
    navigationController?.navigationBar.isHidden = true
    super.viewWillAppear(animated)
}


override func viewWillDisappear(_ animated: Bool) {
    if (navigationController?.topViewController != self) {
        navigationController?.navigationBar.isHidden = false
    }
    super.viewWillDisappear(animated)
}
Eugene Braginets
źródło
czy możesz wyjaśnić, dlaczego sprawdzasz! = siebie?
Kitson
2
@Kitson, sprawdź odpowiedź użytkownika 486646: Jednym drobnym ulepszeniem, które musiałem zrobić w innych odpowiedziach, jest tylko odsłonięcie paska w widoku. Zniknie, jeśli przyczyną jego zniknięcia jest wciśnięty element nawigacyjny. Jest tak, ponieważ widok może zniknąć z innych powodów.
Odsłoniłem
Wygląda na to, że jeśli go użyjesz navcontroller.navagationBarHidden, spowoduje to uszkodzenie całego kontrolera nawigacyjnego (bez przeciągania tam i z powrotem). Aby to zadziałało, użyłem navigationController?.navigationBar.hiddenzamiast tego. Przesuwanie nadal działa i nie pozostawia pustej przestrzeni, ponieważ wydaje się, że znajduje się w widoku stosu lub coś w tym stylu
Sirens
8

Udzielam odpowiedzi @ chad-m.

Oto wersja Swift:

  1. Utwórz nowy plik MyNavigationController.swift

import UIKit

class MyNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
        if viewController == self.viewControllers.first {
            self.setNavigationBarHidden(true, animated: animated)
        } else {
            self.setNavigationBarHidden(false, animated: animated)
        }
    }

}
  1. Ustaw klasę UINavigationController w StoryBoard na MyNavigationController To wszystko!MyNavigationController

Różnica między odpowiedzią chad-m a moją:

  1. Dziedzicz po UINavigationController, więc nie zanieczyszczasz swojego rootViewController.

  2. użyj self.viewControllers.firstzamiast homeViewController, więc nie zrobisz tego 100 razy dla 100 UINavigationControllers w 1 StoryBoard.

AI Lion
źródło
Pomyśl, że to najczystsza odpowiedź. Dzięki
DaSilva,
6

Po wielu próbach dowiedziałem się, jak działało to, czego chciałem. Właśnie tego próbowałem. - Mam widok ze zdjęciem. i chciałem, aby obraz był wyświetlany na pełnym ekranie. - Mam też kontroler nawigacji z paskiem tab. Więc też muszę to ukryć. - Moim głównym wymaganiem było nie tylko ukrywanie się, ale także efekt zanikania podczas pokazywania i ukrywania się.

Tak to działało.

Krok 1 - Mam obraz i użytkownik stuknie go raz. Przechwytuję ten gest i wpycham go w nowy imageViewController, w tym imageViewController, chcę mieć obraz na pełnym ekranie.

- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {  
NSLog(@"Single tap");
ImageViewController *imageViewController =
[[ImageViewController alloc] initWithNibName:@"ImageViewController" bundle:nil];

godImageViewController.imgName  = // pass the image.
godImageViewController.hidesBottomBarWhenPushed=YES;// This is important to note. 

[self.navigationController pushViewController:godImageViewController animated:YES];
// If I remove the line below, then I get this error. [CALayer retain]: message sent to deallocated instance . 
// [godImageViewController release];
} 

Krok 2 - Wszystkie poniższe kroki znajdują się w ImageViewController

Krok 2.1 - W ViewDidLoad pokaż pasek nawigacyjny

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"viewDidLoad");
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}

Krok 2.2 - W viewDidAppearustaw zadanie timera z opóźnieniem (mam ustawione na 1 sekundę opóźnienia). A po opóźnieniu dodaj efekt zanikania. Korzystam z alfa, aby używać zanikania.

- (void)viewDidAppear:(BOOL)animated
{
NSLog(@"viewDidAppear");

myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self     selector:@selector(fadeScreen) userInfo:nil repeats:NO];
}

- (void)fadeScreen
{
[UIView beginAnimations:nil context:nil]; // begins animation block
[UIView setAnimationDuration:1.95];        // sets animation duration
self.navigationController.navigationBar.alpha = 0.0;       // Fades the alpha channel of   this view to "0.0" over the animationDuration of "0.75" seconds
[UIView commitAnimations];   // commits the animation block.  This Block is done.
}

krok 2.3 - Pod viewWillAppeardodaj gest singleTap do obrazu i uczyń pasek nawigacyjny przezroczystym.

- (void) viewWillAppear:(BOOL)animated
{

NSLog(@"viewWillAppear");


NSString *path = [[NSBundle mainBundle] pathForResource:self.imgName ofType:@"png"];

UIImage *theImage = [UIImage imageWithContentsOfFile:path];

self.imgView.image = theImage;

// add tap gestures 
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
[self.imgView addGestureRecognizer:singleTap];  
[singleTap release];  

// to make the image go full screen
self.navigationController.navigationBar.translucent=YES;
}

- (void)handleTap:(UIGestureRecognizer *)gestureRecognizer 
{ 
 NSLog(@"Handle Single tap");
 [self finishedFading];
  // fade again. You can choose to skip this can add a bool, if you want to fade again when user taps again. 
 myTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self  selector:@selector(fadeScreen) userInfo:nil repeats:NO];
 }

Krok 3 - Na koniec viewWillDisappearpamiętaj, aby odłożyć wszystkie rzeczy z powrotem

- (void)viewWillDisappear: (BOOL)animated 
{ 
self.hidesBottomBarWhenPushed = NO; 
self.navigationController.navigationBar.translucent=NO;

if (self.navigationController.topViewController != self)
{
    [self.navigationController setNavigationBarHidden:NO animated:animated];
}

[super viewWillDisappear:animated];
}
Verma
źródło
4

W przypadku, gdy ktoś nadal ma problem z szybkim usunięciem wstecznego błędu, anulował błąd, ponieważ @fabb skomentował w zaakceptowanej odpowiedzi.

Udaje mi się to naprawić, zastępując viewDidLayoutSubviewsdodatkowo, viewWillAppear/viewWillDisappearjak pokazano poniżej:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
}

//*** This is required to fix navigation bar forever disappear on fast backswipe bug.
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.navigationController?.setNavigationBarHidden(false, animated: false)
}

W moim przypadku zauważam, że dzieje się tak, ponieważ kontroler widoku głównego (gdzie nav jest ukryty) i kontroler widoku wypychanego (nav jest pokazany) ma różne style paska stanu (np. Ciemny i jasny). W momencie rozpoczęcia przeciągnięcia wstecz w celu otwarcia kontrolera widoku pojawi się dodatkowa animacja kolorowa paska stanu. Jeśli zwolnisz palec w celu anulowania interaktywnego popu, a animacja paska stanu nie zostanie zakończona , pasek nawigacyjny zniknie na zawsze!

Ten błąd nie występuje jednak, jeśli style paska stanu obu kontrolerów widoku są takie same.

aunnnn
źródło
1

Jeśli chcesz całkowicie ukryć pasek nawigacji w kontrolerze, o wiele czystszym rozwiązaniem jest, aby w kontrolerze głównym mieć coś takiego:

@implementation MainViewController
- (void)viewDidLoad {
    self.navigationController.navigationBarHidden=YES;
    //...extra code on view load  
}

Po naciśnięciu widoku potomnego w kontrolerze pasek nawigacji pozostanie ukryty; jeśli chcesz wyświetlić go tylko w dziecku, dodasz kod do wyświetlania it(self.navigationController.navigationBarHidden=NO;)w viewWillAppearwywołaniu zwrotnym i podobnie kod do ukrywania go naviewWillDisappear

Alex
źródło
0

Najprostszą implementacją może być po prostu sprawdzenie, czy każdy kontroler widoku określa, czy jego pasek nawigacji jest ukryty czy nie w swojej viewWillAppear:animated:metodzie. To samo podejście działa również w przypadku ukrywania / pokazywania paska narzędzi:

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setToolbarHidden:YES/NO animated:animated];
    [super viewWillAppear:animated];
}
SteveCaine
źródło
W rzeczywistości moja sugestia ma sens tylko dla paska narzędzi, ponieważ ukrycie paska nawigacyjnego bez pasującego wywołania pokazującego, że uniemożliwiłoby użytkownikom powrót z bieżącego widoku.
SteveCaine,
0

Ukrywanie paska nawigacyjnego tylko na pierwszej stronie można uzyskać również poprzez scenorys. W serii ujęć goto Navigation Controller Scene-> Pasek nawigacji . I wybierz właściwość „ Ukryty ” w Inspektorze atrybutów . To ukryje pasek nawigacyjny od pierwszego kontrolera widoku, aż stanie się widoczny dla wymaganego kontrolera widoku.

Pasek nawigacji można ustawić ponownie tak, aby był widoczny w wywołaniu zwrotnym ViewWillAppear ViewControllera.

-(void)viewWillAppear:(BOOL)animated {

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];                                                  
}
RSG
źródło
0

Swift 4:

W kontrolerze widoku, przed którym chcesz ukryć pasek nawigacji.

override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
    super.viewWillAppear(animated)
}

override func viewWillDisappear(_ animated: Bool) {
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
    super.viewWillDisappear(animated)
}
John Riselvato
źródło
-1

Wdrażając ten kod w ViewController, możesz uzyskać ten efekt. Właściwie sztuczka polega na tym, że ukryj pasek nawigacji po uruchomieniu tego kontrolera.

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [super viewWillAppear:animated];
}

i odsłoń pasek nawigacji, gdy użytkownik opuści tę stronę, to viewWillDisappear

- (void)viewWillDisappear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [super viewWillDisappear:animated];
}
Dhiru
źródło