ChatGPT解决这个技术问题 Extra ChatGPT

iPhone仅在第一页隐藏导航栏

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

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

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

G
Geri Borbás

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

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 的实现


这完全摇滚!我为此苦苦挣扎了至少一天。谢谢!!!
警告:这会在快速后退时产生一个非常糟糕的错误。假设 A(无导航栏)和 B(有导航栏)被推入堆栈。当在视图 B 上并快速向后滑动时,但提前释放以留在 B 上时,导航栏仍然被隐藏。现在已经没有办法回去了。这是由于 animated=YES。我知道 animated=NO 看起来很难看,但似乎当隐藏导航栏的动画尚未完成时,再次显示它的动画将被忽略。还没有解决办法。
在 Swift 中:覆盖 func viewWillAppear(animated: Bool) { self.navigationController?.setNavigationBarHidden(true, animated: true) super.viewWillAppear(true) } 覆盖 func viewWillDisappear(animated: Bool) { self.navigationController?.setNavigationBarHidden(false,动画:假)super.viewWillDisappear(真)}
问题在 2010 年得到了回答,并在 2015 年底帮助了我!谢谢你。
这就是我所说的传奇答案。绝妙的把戏伙伴。即使在几十年后工作......也迅速实施了同样的工作,完美无瑕。 +1 为您的回答@Alan Rogers
B
Borzh

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

navigationController.delegate = self;

并在 navigationController:willShowViewController:animated: 中使用 setNavigationBarHidden

- (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 的行为的简单方法。


这什么时候会被调用?
完美的解决方案。这应该是公认的答案。谢谢!
完美的答案。如果我们无法在第一个视图控制器上覆盖 viewWillAppear 和 viewWillDisappear 方法,它也可以工作。
惊人的。选择的答案可以正常工作,但仅适用于简单的应用程序。当导航栏位于选项卡控制器中并以各种方式推送/呈现各种 VC 时,此答案有效。
这是最好的答案。最佳答案可能会出现@fabb 描述的错误。
佚名

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

因此,如果此视图不再是最顶层视图,我只会取消隐藏栏:

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

    [super viewWillDisappear:animated];
}

+1,您通常不想在推送模式对话框时显示导航栏。
P
Pablo Santa Cruz

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

像这样你需要隐藏它:

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

像这样你需要展示它:

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

Lee,如果这解决了您的问题,请将 Pablo's 标记为“解决方案”答案。
唯一的问题是当您从一个视图导航到下一个视图时,导航栏会“弹出”并进入视图。是否可以在第一个视图上没有导航栏,当第二个视图滑入到位时,它有导航栏,没有任何弹出?
@henning 要使导航栏按预期滑入/滑出,您需要使用 setNavigationBarHidden:animated:。请参阅下面的 Alan Rogers 的回答(应该真正标记为“解决方案”)。
这个答案有点错误(viewWill/DidAppear)应该调用super。另请参阅下面的我的答案,以获取不需要将其添加到每个视图控制器的解决方案。
C
Community

当前接受的答案与问题中描述的预期行为不匹配。该问题要求将导航栏隐藏在根视图控制器上,但在其他任何地方都可见,但接受的答案会隐藏特定视图控制器上的导航栏。当第一个视图控制器的另一个实例被压入堆栈时会发生什么?即使我们没有查看根视图控制器,它也会隐藏导航栏。

相反,@Chad M. 使用 UINavigationControllerDelegatestrategy 是一个不错的选择,这里有一个更完整的解决方案。脚步:

子类 UINavigationController 实现 -navigationController:willShowViewController:animated 方法,根据是否显示根视图控制器来显示或隐藏导航栏覆盖初始化方法以将 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];
    }
}

这是一个比接受的答案更合适的答案
E
Eugene Braginets

在斯威夫特 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吗?
@Kitson,检查 user486646 的答案:我必须对其他答案进行的一个小调整是仅在 viewWillDisappear 中取消隐藏该栏,如果它消失的原因是由于导航项目被推到它上面。这是因为视图可能因其他原因而消失。因此,如果此视图不再是最顶层视图,我只会取消隐藏栏
似乎如果您使用 navcontroller.navagationBarHidden 它会破坏整个导航控制器(没有来回滑动)。为了让它工作,我改用 navigationController?.navigationBar.hidden。滑动仍然有效,并且不会留下空白空间,因为它似乎在堆栈视图或其他东西中
A
AI Lion

将我的功劳归功于@chad-m 的回答。

这是斯威夫特版本:

创建一个新文件 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)
        }
    }

}

将 StoryBoard 中的 UINavigationController 类设置为 MyNavigationController 就是这样!

chad-m 的答案和我的区别:

从 UINavigationController 继承,所以你不会污染你的 rootViewController。使用 self.viewControllers.first 而不是 homeViewController,因此您不会为 1 个 StoryBoard 中的 100 个 UINavigationController 执行此操作 100 次。


认为这是最干净的答案。谢谢
C
CristiC

经过多次试验,这是我如何让它达到我想要的效果。这就是我正在尝试的。 - 我有一个图像视图。我想让图像全屏显示。 - 我也有一个带有 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 秒延迟)。并在延迟后添加淡入淡出效果。我正在使用 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 下,将单点手势添加到图像并使导航栏半透明。

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

a
aunnnn

如@fabb在接受的答案中评论的那样,如果有人仍然遇到快速后退取消错误的问题。

除了 viewWillAppear/viewWillDisappear 之外,我设法通过覆盖 viewDidLayoutSubviews 来解决此问题,如下所示:

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

在我的例子中,我注意到这是因为根视图控制器(隐藏导航)和推送视图控制器(显示导航)具有不同的状态栏样式(例如深色和浅色)。当您开始向后滑动以弹出视图控制器的那一刻,将会有额外的状态栏颜色动画。如果您松开手指以取消交互弹出,而状态栏动画尚未完成,导航栏将永远消失!

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


P
Paras Joshi

如果您想要将导航栏完全隐藏在控制器中,则更简洁的解决方案是在根控制器中具有以下内容:

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

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


P
Paras Joshi

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

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

实际上,我的建议只对工具栏有意义,因为在没有匹配调用的情况下隐藏导航栏会导致用户无法从当前视图返回。
B
BDL

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

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

-(void)viewWillAppear:(BOOL)animated {

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

J
John Riselvato

斯威夫特 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)
}

D
Dhiru

通过在您的 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];
}