iPhone скрывает панель навигации только на первой странице - PullRequest
365 голосов
/ 10 мая 2009

У меня есть код ниже, который скрывает и показывает навигационную панель. Он скрывается, когда загружается первое представление, а затем скрывается, когда вызывается «потомок» Проблема в том, что я не могу найти событие / действие, которое заставит его скрыться снова, когда они вернутся к корневому представлению ....

У меня есть кнопка «test» на корневой странице, которая выполняет действие вручную, но это не красиво, и я хочу, чтобы оно было автоматическим.

-(void)hideBar 
{
    self.navController.navigationBarHidden = YES;
}
-(void)showBar 
{       
    self.navController.navigationBarHidden = NO;
}

Ответы [ 14 ]

1003 голосов
/ 09 марта 2010

Самое лучшее решение, которое я нашел, - это сделать в контроллере first view .

следующее.

Objective-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];
}

Swift

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

Это приведет к анимированию навигационной панели слева (вместе со следующим представлением), когда вы нажимаете следующий UIViewController в стеке, и анимированию влево (вместе со старым представлением), когда вы нажмите кнопку возврата на UINavigationBar.

Обратите также внимание, что это не делегированные методы, вы переопределяете реализацию этих методов UIViewController, и согласно документации вы должны вызывать реализацию super где-то в вашей реализации .

45 голосов
/ 21 июня 2011

Другой подход, который я нашел, - установить делегата для NavigationController:

navigationController.delegate = self;

и используйте setNavigationBarHidden в navigationController: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];
}

Простой способ настроить поведение для каждого ViewController в одном месте.

17 голосов
/ 20 ноября 2010

Один небольшой трюк, который я должен был сделать для других ответов, - это только показать панель в viewWillDisappear, если причина, по которой он исчезает, связана с нажатием на него элемента навигации. Это потому, что вид может исчезнуть по другим причинам.

Так что я могу только показать панель, если этот вид больше не является самым верхним:

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

    [super viewWillDisappear:animated];
}
16 голосов
/ 10 мая 2009

Я бы поместил код в делегат viewWillAppear для каждого отображаемого представления:

Вот так, где вам нужно это скрыть:

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

Вот так, где вам нужно показать это:

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject showBar];
}
14 голосов
/ 05 февраля 2015

в 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)
}
12 голосов
/ 09 октября 2014

В настоящее время принятый ответ не соответствует предполагаемому поведению, описанному в вопросе. Вопрос требует, чтобы панель навигации была скрыта на корневом контроллере представления, но видна везде, но принятый ответ скрывает панель навигации на конкретном контроллере представления. Что происходит, когда другой экземпляр первого контроллера представления помещается в стек? Она скроет панель навигации, даже если мы не смотрим на контроллер корневого представления.

Вместо этого, стратегия @Chad M. использования UINavigationControllerDelegate является хорошей, и вот более полное решение. Шаги:

  1. Подкласс UINavigationController
  2. Реализуйте метод -navigationController:willShowViewController:animated, чтобы показать или скрыть панель навигации в зависимости от того, показывает ли она контроллер корневого представления
  3. Переопределить методы инициализации, чтобы установить подкласс UINavigationController в качестве своего собственного делегата

Полный код для этого решения можно найти в this Gist . Вот реализация navigationController:willShowViewController:animated:

- (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];
    }
}
6 голосов
/ 11 декабря 2011

После нескольких испытаний вот как я получил это работает на то, что я хотел. Это то, что я пытался. - У меня есть вид с изображением. и я хотел, чтобы изображение было полноэкранным. - У меня есть навигационный контроллер с TabBar тоже. Так что мне тоже нужно это скрывать. - Кроме того, моим главным требованием было не просто скрытие, но и эффект затухания при показе и скрытии.

Вот так я и заработал.

Шаг 1 - У меня есть изображение, и пользователь нажимает на него один раз. Я фиксирую этот жест и вставляю его в новый imageViewController, в imageViewController, я хочу получить полноэкранное изображение.

- (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];
} 

Шаг 2 - Все эти шаги ниже находятся в ImageViewController

Шаг 2.1 - В ViewDidLoad показать navBar

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

Шаг 2.2 - В viewDidAppear установите задачу таймера с задержкой (у меня она установлена ​​на задержку в 1 секунду). А после задержки добавьте эффект затухания. Я использую альфа, чтобы использовать затухание.

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

шаг 2.3 - В разделе viewWillAppear добавьте жест SingleTap к изображению и сделайте navBar полупрозрачным.

- (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];
 }

Шаг 3 - Наконец, в viewWillDisappear, убедитесь, что вернули все вещи обратно

- (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];
}
4 голосов
/ 26 сентября 2018

Отдайте должное ответу @ chad-m.

Вот версия Swift:

  1. Создать новый файл 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. Установите класс вашего UINavigationController в StoryBoard равным MyNavigationController MyNavigationController Вот и все!

Разница между ответом Чад-м и моим:

  1. Наследовать от UINavigationController, чтобы вы не загрязняли свой rootViewController.

  2. используйте self.viewControllers.first вместо homeViewController, поэтому вы не будете делать это 100 раз для ваших 100 контроллеров UINavigation в 1 StoryBoard.

3 голосов
/ 02 августа 2016

В случае, если у кого-то все еще есть проблемы с быстрым обратным вызовом , аннулируется ошибка , как @fabb прокомментировал в принятом ответе.

Мне удается это исправить, переопределив viewDidLayoutSubviews, в дополнение к viewWillAppear/viewWillDisappear, как показано ниже:

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

В моем случае, я заметил, что это потому, что контроллер корневого представления (где скрыта навигация) и контроллер удаленного просмотра (отображается навигация) имеет разные стили строки состояния (например, темный и светлый) , В тот момент, когда вы запускаете обратную прокрутку, чтобы открыть контроллер представления, появится дополнительная цветовая анимация строки состояния. Если вы отпустите палец, чтобы отменить интерактивное всплывающее окно, , пока анимация строки состояния не завершена , панель навигации исчезнет навсегда!

Однако эта ошибка не возникает, если стили строки состояния обоих контроллеров представления совпадают.

1 голос
/ 11 мая 2009

Если вы хотите полностью скрыть панель навигации в контроллере, гораздо более чистое решение состоит в том, чтобы в корневом контроллере было что-то вроде:

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

Когда вы нажимаете дочерний вид в контроллере, панель навигации остается скрытой; если вы хотите отобразить его только в дочернем элементе, вы добавите код для отображения it(self.navigationController.navigationBarHidden=NO;) в обратном вызове viewWillAppear и аналогичный код для его скрытия на viewWillDisappear

...