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

383

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

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

-(void)hideBar 
{
    self.navController.navigationBarHidden = YES;
}
-(void)showBar 
{       
    self.navController.navigationBarHidden = NO;
}
Ли Армстронг
источник

Ответы:

1036

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

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

стриж

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 где-то в вашей реализации .

Алан Роджерс
источник
2
Это совершенно потрясающе! Я боролся с этим по крайней мере один день. Спасибо!!!
Джеймс Теста
26
ВНИМАНИЕ: Это создает очень серьезную ошибку при быстром обратном смахивании. Предположим, что A (без навигационной панели) и B (с навигационной панелью) помещены в стек. Когда вы просматриваете B и делаете быстрое обратное движение, но отпустите достаточно рано, чтобы остаться на B, панель навигации все еще будет скрыта. Теперь нет пути назад. Это связано animated=YES. Я знаю, это выглядит некрасиво animated=NO, но кажется, что когда анимация для скрытия панели навигации еще не закончена, анимация для ее отображения снова игнорируется. Решения пока нет.
Фабб
3
В Swift: переопределить func viewWillAppear (animated: Bool) {self.navigationController? .SetNavigationBarHidden (true, animated: true) super.viewWillAppear (true)} переопределить func viewWillDisappear (animated: Bool) {self.navigationController?. animated: false) super.viewWillDisappear (true)}
Китсон,
7
На вопрос ответили в 2010 году и помогает мне в конце 2015 года! Спасибо.
oyalhi
1
Вот что я называю легендарным ответом. Превосходный трюк, приятель. Даже работая спустя десятилетия ... Реализовано так же быстро, работает без нареканий. +1 за ваш ответ @ Алан Роджерс
onCompletion
62

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

Чад М.
источник
Когда это будет вызвано?
Залак Патель
1
Идеальное решение. Это должен быть принятый ответ. Спасибо!
Сама
Идеальный ответ. Это также работает в случае, если мы не можем переопределить методы viewWillAppear и viewWillDisappear на первом контроллере представления.
pjuzeliunas
1
Потрясающие. Выбранный ответ работает нормально, но только в простых приложениях. Этот ответ работает, когда панель навигации находится в контроллере вкладок и по-разному нажимает / представляет различные VC.
Джонатан Вингер-Ланг
Это лучший ответ. В верхнем ответе может быть ошибка, как в описании @ fabb .
Ryan.Yuen
19

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

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

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

    [super viewWillDisappear:animated];
}

источник
3
+1, вы обычно не хотите показывать панель навигации при нажатии модального диалога.
Жоао Портела
18

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

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

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

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

- (void)viewWillAppear:(BOOL)animated
{
        [yourObject showBar];
}
Пабло Санта Круз
источник
Ли, если это решило твою проблему, отметь ответ Пабло как «решение».
Рог
2
Единственная проблема заключается в том, что панель навигации «всплывает» и отображается, когда вы переходите от одного вида к другому. Возможно ли просто, чтобы навигационная панель отсутствовала в первом представлении, и когда второй вид вставляется на свое место, он имеет навигационную панель без каких-либо всплывающих окон?
Хеннинг
2
@henning Для того, чтобы NavBar скользил так, как вы ожидаете, вам нужно использовать setNavigationBarHidden: animated :. Смотрите ответ Алана Роджерса ниже (который действительно должен быть помечен как «решение»).
Ник Фордж
2
Этот ответ немного неправильный (viewWill / DidAppear) должен вызывать супер. Также смотрите мой ответ ниже для решения, где вам не нужно добавлять его в КАЖДЫЙ контроллер представления.
Алан Роджерс
15

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

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

  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];
    }
}
hunteros
источник
2
Это более уместный ответ, чем принятый
Павел Гуров
14

в Свифте 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)
}
Евгений Брагинец
источник
Не могли бы вы объяснить, почему вы проверяете себя!
Китсон
2
@Kitson, проверьте user486646 'ответ: один небольшой трюк, который я должен был сделать на других ответах, - это только показать панель в viewWillDisappear, только если она исчезла из-за нажатия на нее элемента навигации. Это потому, что вид может исчезнуть по другим причинам. Так что я показываю бар только в том случае, если этот вид больше не является самым верхним
Юджин Брагинец,
Кажется, что если вы используете navcontroller.navagationBarHiddenего, он сломает весь навигационный контроллер (без пролистывания туда-сюда). Чтобы заставить его работать, я использовал navigationController?.navigationBar.hiddenвместо этого. Смахивание все еще работает, и оно не оставляет пустого пространства, потому что кажется, что оно находится внутри стека или что-то в этом роде
Сирены,
8

Отдай должное ответу @ 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.

AI Lion
источник
Думаю, это самый чистый ответ. Спасибо
DaSilva
6

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

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

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

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

aunnnn
источник
1

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

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

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

Alex
источник
0

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

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

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

Навигационная панель может быть установлена ​​обратно видимой в обратном вызове ViewWillAppear ViewController.

-(void)viewWillAppear:(BOOL)animated {

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];                                                  
}
RSG
источник
0

Свифт 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)
}
Джон Риселвато
источник
-1

Внедрив этот код в свой 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];
}
Dhiru
источник