iPhone скрывает панель навигации только на первой странице

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

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

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

person Lee Armstrong    schedule 10.05.2009    source источник


Ответы (14)


Лучшее решение, которое я нашел, - это сделать следующее в первом контроллере представления.

Цель-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 где-нибудь в своей реализации.

person Alan Rogers    schedule 09.03.2010
comment
Это потрясающе! Я боролся с этим как минимум день. Спасибо!!! - person James Testa; 27.09.2011
comment
Я думал, что рамка просмотра изменится, но это происходит до viewDidAppear: :( Так что, если вам нужен точный кадр после скрытия панели навигации, это не решение. - person Herz Rod; 22.03.2013
comment
Верхняя панель моего второго контроллера просмотра также скрыта :( - person coolcool1994; 10.05.2013
comment
приятное, но неопределенное поведение для нескольких венчурных капиталистов, у которых панель навигации может быть скрыта, а может и не быть .... - person Sam; 19.11.2013
comment
В iOS 7, используя непрозрачную панель навигации, все мои представления помещаются под экран. Я предполагаю, что мне следует одновременно изменить размер своих представлений, но я не уверен, какой именно метод вызывать или где его вызывать. Любая помощь? - person oflannabhra; 15.04.2014
comment
Кто-нибудь знает, почему кажется, что в rootVC можно только показать / скрыть навигационную панель? - person Weston; 30.07.2014
comment
ВНИМАНИЕ! Это создает очень серьезную ошибку при быстром обратном пролистывании. Предположим, что A (без панели навигации) и B (с панелью навигации) помещены в стек. Когда вы находитесь на виде B и выполняете быстрое обратное пролистывание, но отпускаете достаточно рано, чтобы оставаться на B, навигационная панель по-прежнему скрывается. Теперь нет возможности вернуться назад. Это связано с animated=YES. Я знаю, что с animated=NO это выглядит некрасиво, но кажется, что когда анимация для скрытия панели навигации еще не завершена, анимация для ее повторного отображения игнорируется. Пока нет решения. - person fabb; 24.04.2015
comment
В Swift: переопределить функцию viewWillAppear (animated: Bool) {self.navigationController? .SetNavigationBarHidden (true, animated: true) super.viewWillAppear (true)} переопределить функцию viewWillDisappear (animated: Bool) {self.navigationController? .SetNavigationBarHidden (false) Animated: false) super.viewWillDisappear (true)} - person Kitson; 28.09.2015
comment
Да, я использую делегат контроллера навигации. При обратном пролистывании это не так хорошо, поскольку только когда обратное пролистывание завершено, состояние панели навигации можно адаптировать, поскольку неизвестно, будет ли обратное пролистывание прервано или нет. - person fabb; 29.10.2015
comment
На вопрос был дан ответ в 2010 году, и он помогает мне в конце 2015 года! Спасибо. - person oyalhi; 08.12.2015
comment
Вот что я называю легендарным ответом. Превосходный трюк товарищ. Даже работая спустя десятилетия ... Реализовано то же самое быстро, работает безупречно. +1 за ваш ответ @Alan Rogers - person onCompletion; 21.05.2016
comment
Все еще держится в 2016 году! - person JBone; 02.06.2016
comment
@Alan, Спасибо за решение. - person Mohammad Zaid Pathan; 24.06.2016
comment
Пожалуйста, обновите свой ответ и введите код после звонка в super - person thibaut noah; 30.06.2018
comment
Поскольку это принятый и наиболее популярный ответ, вам следует подумать о том, чтобы отредактировать решение, чтобы включить другое (и действительно правильное) исправление: ознакомьтесь с ответом @Chad M. - person Borzh; 04.10.2018

Другой подход, который я нашел, - установить делегата для 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 в одном месте.

person Chad M.    schedule 20.06.2011
comment
Когда это будет вызвано? - person Zalak Patel; 21.11.2014
comment
Идеальное решение. Это должен быть принятый ответ. Спасибо! - person Samah; 02.02.2016
comment
Отличный ответ. Это также работает, если мы не можем переопределить методы viewWillAppear и viewWillDisappear на первом контроллере представления. - person pjuzeliunas; 26.10.2016
comment
Потрясающие. Выбранный ответ работает нормально, но только в простых приложениях. Этот ответ работает, когда панель навигации находится в контроллере вкладок и различными способами толкает / представляет различные VC. - person jontelang; 17.03.2017
comment
Это лучший ответ. Верхний ответ может содержать ошибку в описании @ fabb. - person Runryan; 28.08.2018
comment
Это очень хорошее решение для MoreNavigationController из UITabBarController. Должен быть действительно принятый ответ. - person Borzh; 04.10.2018
comment
Спасибо! ты герой! - person Hugo Vanderlei; 11.03.2019

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

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

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

    [super viewWillDisappear:animated];
}
person Community    schedule 20.11.2010
comment
+1, вы обычно не хотите показывать панель навигации при нажатии модального диалога. - person João Portela; 11.11.2011

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

Вот так, где это нужно спрятать:

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

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

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject showBar];
}
person Pablo Santa Cruz    schedule 10.05.2009
comment
Ли, если это устранило вашу проблему, отметьте ответ Пабло как ответ. - person Rog; 10.05.2009
comment
Единственная проблема заключается в том, что панель навигации выскакивает наружу и становится видимой при переходе от одного представления к другому. Возможно ли, чтобы панель навигации отсутствовала в первом представлении, а когда второе представление вставляется на место, на нем появляется панель навигации без каких-либо всплывающих окон? - person Henning; 06.11.2009
comment
@henning Чтобы заставить NavBar выдвигаться / выдвигаться, как и следовало ожидать, вам нужно использовать setNavigationBarHidden: animated :. См. Ответ Алана Роджерса ниже (который действительно должен быть отмечен как решение). - person Nick Forge; 10.03.2010
comment
Этот ответ немного неверен (viewWill / DidAppear) должен вызывать super. Также см. Мой ответ ниже для решения, в котором вам не нужно добавлять его в КАЖДЫЙ контроллер представления. - person Alan Rogers; 19.03.2010

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

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

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

Полный код этого решения можно найти в этом 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];
    }
}
person hunteros    schedule 09.10.2014
comment
Это более подходящий ответ, чем принятый - person Pavel Gurov; 21.03.2016

в 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)
}
person Eugene Braginets    schedule 05.02.2015
comment
не могли бы вы объяснить, почему вы проверяете! = self? - person Kitson; 28.09.2015
comment
@Kitson, проверьте ответ user486646 ': Одна небольшая настройка, которую мне пришлось внести в другие ответы, - это показать панель в viewWillDisappear только в том случае, если причина, по которой она исчезает, связана с нажатием на нее элемента навигации. Это потому, что представление может исчезнуть по другим причинам. Поэтому я показываю панель только в том случае, если это представление больше не является самым верхним - person Eugene Braginets; 28.09.2015
comment
Кажется, что если вы используете navcontroller.navagationBarHidden, он сломает весь контроллер навигации (без свайпов назад и вперед). Чтобы заставить его работать, я вместо этого использовал navigationController?.navigationBar.hidden. Свайп по-прежнему работает, и он не оставляет пустого места, потому что кажется, что он находится внутри стека или чего-то еще. - person Allison; 24.04.2016

Отдаю должное ответу @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 Вот и все!

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

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

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

person AI Lion    schedule 26.09.2018
comment
Думаю, это самый ясный ответ. Спасибо - person DaSilva; 05.03.2019

Вот как я добился того, что я хотел, после нескольких испытаний. Это то, что я пытался. - У меня есть вид с изображением. и я хотел, чтобы изображение отображалось в полноэкранном режиме. - У меня тоже есть контроллер навигации с 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 отобразите панель навигации

- (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 к изображению и сделайте панель навигации полупрозрачной.

- (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];
}
person verma    schedule 11.12.2011

Если у кого-то все еще возникают проблемы с ошибкой отмены быстрого обратного пролистывания, как прокомментировал @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)
}

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

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

person aunnnn    schedule 02.08.2016

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

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

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

person Alex    schedule 11.05.2009

Самая простая реализация может заключаться в том, чтобы каждый контроллер представления указывал, скрыта ли его панель навигации или нет, в его viewWillAppear:animated: методе. Тот же подход хорошо работает и для скрытия / отображения панели инструментов:

- (void)viewWillAppear:(BOOL)animated {
    [self.navigationController setToolbarHidden:YES/NO animated:animated];
    [super viewWillAppear:animated];
}
person SteveCaine    schedule 30.11.2011
comment
На самом деле, мое предложение имеет смысл только для панели инструментов, поскольку скрытие панели навигации без соответствующего вызова, чтобы показать, что она оставит пользователей неспособными вернуться назад из текущего представления. - person SteveCaine; 04.12.2011

Скрыть панель навигации только на первой странице можно также с помощью раскадровки. В раскадровке перейдите к Сцена контроллера навигации-> Панель навигации. И выберите свойство «Скрытый» в инспекторе атрибутов. Это скроет панель навигации, начиная с первого viewcontroller, пока она не станет видимой для требуемого viewcontroller.

Панель навигации можно снова сделать видимой в обратном вызове ViewController ViewWillAppear.

-(void)viewWillAppear:(BOOL)animated {

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];                                                  
}
person RGhate    schedule 23.02.2017

Swift 4:

В контроллере представления, от которого вы хотите скрыть панель навигации.

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)
}
person John Riselvato    schedule 20.02.2018

Реализуя этот код в своем ViewController, вы можете получить этот эффект. На самом деле хитрость заключается в том, чтобы скрыть панель навигации при запуске этого контроллера.

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

и отобразить панель навигации, когда пользователь покинет эту страницу, сделайте это viewWillDisappear

- (void)viewWillDisappear:(BOOL)animated {
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [super viewWillDisappear:animated];
}
person Dhiru    schedule 02.08.2016