iPhone仅在第一页上隐藏导航栏


381

我下面有隐藏和显示导航栏的代码。当第一个视图加载时,它将隐藏,然后在调用“子项”时将其隐藏。麻烦的是,当他们回到根视图时,我找不到触发它再次隐藏的事件/动作...。

我在根页面上有一个“测试”按钮,该按钮可以手动执行操作,但它并不漂亮,我希望它是自动的。

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

Answers:


1035

我发现最好的解决方案是在第一个视图控制器中执行以下操作。

目标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
这完全是摇滚!我已经为此奋斗了至少一天。谢谢!!!
James Testa

26
警告:进行快速后掠时,这会造成非常严重的错误。假设将A(无导航栏)和B(有导航栏)推入堆栈。在视图B上进行快速后掠,但释放得足够早以留在视图B上时,导航栏仍被隐藏。现在没有办法回去了。这是由于animated=YES。我知道用看起来很丑animated=NO,但是似乎当用于隐藏导航栏的动画尚未完成时,用于再次显示它的动画就被忽略了。尚无解决方案。
fabb

3
在Swift中:覆盖func viewWillAppear(动画:Bool){self.navigationController?.setNavigationBarHidden(true,animation:true)super.viewWillAppear(animated:Bool){self.navigationController?.setNavigationBarHidden(false,动画:false)super.viewWillDisappear(true)}
Kitson

7
问题在2010年得到了回答,并在2015年年底对我有所帮助!谢谢。
oyalhi 2015年

1
这就是我所说的传奇答案。精湛的把戏。即使经过几十年的工作,也可以迅速,完美地实施。+1为您的答案@艾伦·罗杰斯
onComplete

62

我发现的另一种方法是为设置委托NavigationController

navigationController.delegate = self;

并使用setNavigationBarHiddennavigationController: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在一个地方自定义每种行为的简便方法。


什么时候可以打电话给我?
Zalak Patel 2014年

1
完美的解决方案。这应该是公认的答案。谢谢!
萨玛

完美的答案。如果我们无法在第一个视图控制器上覆盖viewWillAppear和viewWillDisappear方法,它也可以工作。
pjuzeliunas 2016年

1
太棒了 选择的答案可以,但是仅在简单的应用程序中有效。当导航栏位于选项卡控制器中并以各种方式推送/显示各种VC时,此答案有效。
乔纳森边锋郎

这是最好的答案。最佳答案可能是@ fabb的描述所引起的错误。
Ryan.Yuen

18

我必须对其他答案进行的一项细微调整是,如果消失的原因是由于将导航项推到了它,则仅取消隐藏viewWillDisappear中的条。这是因为视图可能由于其他原因而消失。

因此,仅当此视图不再是最高视图时,我才取消隐藏栏:

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

    [super viewWillDisappear:animated];
}

3
+1,通常不希望在按下模式对话框时显示导航栏。
若昂里斯本

17

我会将代码放在显示的每个视图的viewWillAppear委托中:

这样,您需要将其隐藏:

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

这样,您需要显示它:

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

Lee,如果这解决了您的问题,请将Pablo's标记为“解决方案”答案。
罗格

2
唯一的问题是,当您从一个视图导航到另一个视图时,导航栏会“弹出”并进入视图。是否有可能只在第一个视图上没有导航栏,而当第二个视图滑入到位时,它具有导航栏却没有弹出?
亨宁

2
@henning要使NavBar滑入/滑出,您需要使用setNavigationBarHidden:animated:。请参阅下面的艾伦·罗杰斯(Alan Rogers)的答案(应将其真正标记为“解决方案”)。
尼克·福奇

2
这个答案有点错误(viewWill / DidAppear)应该调用super。另请参阅以下我的答案,以获取无需将其添加到每个视图控制器的解决方案。
艾伦·罗杰斯

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

2
这比接受一个更合适的答案
帕维尔·古罗夫

14

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

您能解释一下为什么要检查!= self吗?
杰森2015年

2
@Kitson,检查user486646的答案: 我必须对其他答案进行的一些细微调整是,如果消失的原因是由于将导航项推到了它,则仅取消隐藏viewWillDisappear中的栏。这是因为视图可能由于其他原因而消失。因此,只有在该视图不再是最高视图时,我才会取消隐藏该栏
Eugene Braginets

看来,如果使用,navcontroller.navagationBarHidden它将破坏整个导航控制器(不会来回滑动)。为了使其正常工作,我navigationController?.navigationBar.hidden改用了。滑动仍然有效,并且不会留下任何空白空间,因为它似乎在stackview之类的东西中
Sirens

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. 将StoryBoard中的UINavigationController的类设置为MyNavigationController 就是这样!MyNavigationController

乍得的答案和我的答案之间的区别:

  1. 从UINavigationController继承,因此您不会污染rootViewController。

  2. 使用self.viewControllers.first而不是homeViewController,因此您不会在1个StoryBoard中为100个UINavigationControllers进行100次操作。


认为这是最干净的答案。谢谢
DaSilva '19

6

经过多次试用后,这就是我如何使其按需工作的方式。这就是我正在尝试的。-我有一张图片。我想让图像全屏显示。-我也有一个带有tabBar的导航控制器。所以我也需要隐藏它。-另外,我的主要要求不仅是隐藏,而且在显示和隐藏时也具有褪色效果。

这就是我的工作方式。

步骤1-我有一张图片,用户点击该图片一次。我捕获了该手势并将其推入新的手势imageViewControllerimageViewController,我想要获得全屏图像。

- (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秒延迟)。并在延迟后增加衰落效果。我正在使用Alpha淡入淡出。

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

在我的情况下,我注意到这是因为根视图控制器(隐藏了nav)和推送视图控制器(显示了nav)具有不同的状态栏样式(例如,暗和亮)。当您开始向后滑动以弹出视图控制器时,将出现其他状态栏颜色动画。如果在状态栏动画尚未完成的情况下松开手指以取消交互式弹出,导航栏将永远消失!

但是,如果两个视图控制器的状态栏样式相同,则不会发生此错误。


1

如果您想要将导航栏完全隐藏在控制器中,那么一个更干净的解决方案是在根控制器中添加以下内容:

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

当您在控制器中按下子视图时,导航栏将保持隐藏状态。如果您只想在子级中显示它,您将添加用于it(self.navigationController.navigationBarHidden=NO;)viewWillAppear回调中显示的代码,以及类似的用于将其隐藏在代码中的代码viewWillDisappear


0

最简单的实现可能是仅让每个视图控制器指定其导航栏是否在其viewWillAppear:animated:方法中隐藏。同样的方法也可以很好地用于隐藏/显示工具栏:

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

实际上,我的建议仅对工具栏有意义,因为隐藏导航栏而不显示匹配的调用将使用户无法从当前视图向后导航。
SteveCaine 2011年

0

也可以通过情节提要来实现仅在首页上隐藏导航栏。在情节提要上,转到“ 导航控制器场景”->“导航栏”。然后从“ 属性”检查器中选择“ 隐藏 ”属性。这将从第一个viewcontroller开始隐藏导航栏,直到对所需的viewcontroller可见为止。

可以将导航栏设置回在ViewController的ViewWillAppear回调中可见。

-(void)viewWillAppear:(BOOL)animated {

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];                                                  
}

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中实现此代码,您可以获得这种效果。实际上,窍门是,在启动Controller时隐藏navigationBar

- (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];
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.