【问题标题】:hidesBottomBarWhenPushed = NO not working?hidesBottomBarWhenPushed = NO 不工作?
【发布时间】:2011-08-04 05:31:19
【问题描述】:

我的应用程序中有一个UITabBar,通过将此行放入AppDelegate,我将其隐藏在第一个选项卡中的第一个UIViewController

// ... in MyAppDelegate.m
firstViewController.hidesBottomBarWhenPushed = YES;

firstViewController 中,用户可以推送UIButton,在同一选项卡中推送新的UIViewController。我希望UITabBar 在发生这种情况时再次可见。我试图让它像这样回来:

//... in firstViewController.m

secondViewController = [[SecondViewController alloc] init];
secondViewController.hidesBottomBarWhenPushed = NO;
[[self navigationController] pushViewController:secondViewController animated:YES];

很遗憾,没有带回UITabBar。它仍然隐藏。

如何在隐藏UITabBar 后正确将其带入 bar?

提前致谢。

【问题讨论】:

    标签: iphone objective-c uitabbarcontroller uitabbar


    【解决方案1】:

    我认为您误解了 hidesBottomBarWhenPushed 的使用。如果是,底部栏保持隐藏,直到视图控制器从堆栈中弹出。

    如果我正确理解你的问题:

    secondViewController 应该是 YES,firstViewController 应该是 NO。

    【讨论】:

    • 我想我确实做对了。我不希望标签栏显示在第一个标签的第一个 ViewController 上。但是,我确实希望它出现在第一个选项卡的第二个 ViewController 上。我知道这很奇怪,但在应用程序的上下文中它是有意义的。
    【解决方案2】:

    hidesBottomBarWhenPushed 的文档是这样说的(强调):

    如果是,底部栏保持隐藏状态直到视图控制器从堆栈中弹出。

    所以看起来你看到的行为正是文档所说的那样。您首先将视图控制器推送到具有hidesBottomBarWhenPushed = YES 的堆栈上。此时,将其他视图控制器推入堆栈不会改变底栏的隐藏性。只要第一个视图控制器在堆栈中,底栏就会保持隐藏状态。

    所以我认为你必须想出一种不同的方式来实现你的 UI 目标。一种选择是将第一个视图控制器呈现为标签栏控制器视图上的模式视图控制器。然后,当您想转到第二个视图控制器时,只需关闭第一个视图控制器,瞧。唯一的视觉区别是过渡动画。

    当然还有其他选择,但这只是我想到的。

    祝你好运!

    【讨论】:

    • 啊,这就解释了,谢谢。我真的希望它是“直到一个新的视图控制器被推送到堆栈或从堆栈中弹出”,但是你能做什么?我现在正在寻找替代方案。
    • 是的,很糟糕。试试模态视图控制器。祝你好运!
    【解决方案3】:

    不确定是否找到了解决方案,但我只是设法让它工作。

    我的场景:

    我有一个UITabBarController,有 4 个标签栏项目。 在其中一个标签栏项目上,它加载了一个带有按钮的UIViewController。按钮调用IBOutlet 函数,该函数加载另一个UIViewController,其中包含底部的标签栏。

    经过多次尝试和错误......

    IBOutlet 函数上,我执行以下操作:

    {
     self.hidesBottomBarWhenPushed = YES;
     /* Push the new controller with tab bar */
    }
    

    UITabBarController's 标签栏向左滑动,而我的标签栏从被推送的控制器中向右滑动,效果很好。

    显然,从功能的角度来看,我需要在“返回”时将初始的 UITabBarController's tar 栏推回。

    经过多次尝试和错误......

    我在UIViewController 中有方法viewWillDisappearUIViewController 与标签栏作为:

    - (void) viewWillDisappear:(BOOL)animated
    {
        self.hidesBottomBarWhenPushed = NO;
    }
    

    我在模拟器中对此进行了一些快速测试,它似乎工作正常。

    一些贡献者认为这是一个糟糕的 UI,但我现在正在尝试这个,看看它是如何工作的。

    很高兴收到(警察)任何反馈。 :)

    【讨论】:

      【解决方案4】:

      这个对我有用。 感谢此处其他线程中的提示,我找到了一种解决方案,可以仅为一个视图控制器隐藏标签栏,并为从内部调用的任何视图控制器重新建立它。

      这样做,我可以保持导航控制器的常规链。

      这就是我最终得到的:

      #define kTabBarHeight               49 // This may be different on retina screens. Frankly, I have not yet tried.
      
      - (void) hideTabBar:(BOOL)hide {
      
          // fetch the app delegate
          AppDelegate         *delegate   = [[UIApplication sharedApplication] delegate];
      
          // get the device coordinates
          CGRect              bounds      = [UIScreen mainScreen].bounds;
          float               width;
          float               height;
      
          // Apparently the tab bar controller's view works with device coordinates  
          // and not with normal view/sub view coordinates
          // Therefore the following statement works for all orientations. 
          width                   = bounds.size.width;
          height                  = bounds.size.height;
      
          if (hide) {
      
              // The tab bar should be hidden too. 
              // Otherwise it may flickr up a moment upon rotation or 
              // upon return from detail view controllers. 
              [self.tabBarController.tabBar setHidden:YES];
      
              // Hiding alone is not sufficient. Hiding alone would leave us with an unusable black
              // bar on the bottom of the size of the tab bar. 
              // We need to enlarge the tab bar controller's view by the height of the tab bar. 
              // Doing so the tab bar, although hidden, appears just beneath the screen. 
              // As the tab bar controller's view works in device coordinations, we need to enlarge 
              // it by the tab bar height in the appropriate direction (height in portrait and width in landscape)
              // and in reverse/upside down orientation we need to shift the area's origin beyond zero. 
              switch (delegate.tabBarController.interfaceOrientation) {
                  case UIInterfaceOrientationPortrait:
                      // Easy going. Just add the space on the bottom.
                      [self.tabBarController.view setFrame:CGRectMake(0,0,width,height+kTabBarHeight)];
                      break;
      
                  case UIInterfaceOrientationPortraitUpsideDown:
                      // The bottom is now up! Add the appropriate space and shift the rect's origin to y = -49
                      [self.tabBarController.view setFrame:CGRectMake(0,-kTabBarHeight,width,height+kTabBarHeight)];
                      break;
      
                  case UIInterfaceOrientationLandscapeLeft:
                      // Same as Portrait but add the space to the with but the height
                      [self.tabBarController.view setFrame:CGRectMake(0,0,width+kTabBarHeight,height)];
                      break;
      
                  case UIInterfaceOrientationLandscapeRight:
                      // Similar to Upside Down: Add the space and shift the rect. Just use x and with this time
                      [self.tabBarController.view setFrame:CGRectMake(0-kTabBarHeight,0,width+kTabBarHeight,height)];
                      break;
      
                  default:
                      break;
              }
          } else {
              // reset everything to its original state. 
              [self.tabBarController.view setFrame:CGRectMake(0,0,width,height)];
              [self.tabBarController.tabBar setHidden:NO];
          }
      
          return; 
      }
      
      
      - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
      
          // It is important to call this method at all and to call it here and not in willRotateToInterfaceOrientation
          // Otherwise the tab bar will re-appear. 
          [self hideTabBar:YES];
      
          // You may want to re-arrange any other views according to the new orientation
          // You could, of course, utilize willRotateToInterfaceOrientation instead for your subViews. 
      }
      
      - (void)viewWillAppear: (BOOL)animated { 
      
          // In my app I want to hide the status bar and navigation bar too. 
          // You may not want to do that. If so then skip the next two lines. 
          self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
          [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
      
          [self hideTabBar: YES];
      
          // You may want to re-arrange your subviews here. 
          // Orientation may have changed while detail view controllers were visible. 
          // This method is called upon return from pushed and pulled view controllers.   
      
          return;
      }
      
      - (void)viewWillDisappear: (BOOL)animated {     
      
          // This method is called while this view controller is pulled
          // or when a sub view controller is pushed and becomes visible
          // Therefore the original settings for the tab bar, navigation bar and status bar need to be re-instated
      
          [self hideTabBar:NO];
      
          // If you did not change the appearance of the navigation and status bar in viewWillAppear,
          // then you can skip the next two statements too. 
          self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
          [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
      
          return;
      }
      

      内嵌 cmets 应解释每个语句的推理。不过,可能有更聪明的编码方式。

      隐藏状态栏和导航栏也有一个副作用,我不想对你们隐藏。 1. 当从这个导航控制器返回到调用导航控制器时,调用控制器上的状态栏和导航栏会重叠,直到设备旋转一次或直到另一个选项卡出现后再次选择相关选项卡。 2. 当调用视图控制器是一个表格视图并且当设备在返回表格时处于横向模式时,表格以适合横向的方向显示,但它的布局就像它是纵向的一样。左上角很好,但一些表格单元格和标签栏隐藏在屏幕下方。右侧有一些空闲空间。这也可以通过再次旋转设备来解决。

      一旦我找到这些小但令人讨厌的错误的解决方案,我会及时通知您。

      【讨论】:

        【解决方案5】:

        使用

        secondViewController.hidesBottomBarWhenPushed = NO;
        

        当插入一些操作时

        firstViewController.hidesBottomBarWhenPushed = YES;
        

        【讨论】:

          【解决方案6】:

          我想出了一个非常简单的方法来通过子类化UINavigationController 来解决这个问题。您可以通过使用具有关联对象的类别来完成同样的事情,但我已经有一个子类,所以我只是将代码扔在那里。

          首先,向 UINavigationController 添加一个 ivar:

          @interface CustomNavigationController ()
          {
              NSMutableSet *_viewControllersWithHiddenBottomBar;
          }
          
          @end
          

          然后我重写 push 和 pop 方法来接管处理隐藏逻辑:

          - (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
          {
              if(viewController.hidesBottomBarWhenPushed)
              {
                  viewController.hidesBottomBarWhenPushed = NO;
                  [_viewControllersWithHiddenBottomBar addObject:viewController];
                  [self rootViewController].hidesBottomBarWhenPushed = YES;
              }
              else
              {
                  [self rootViewController].hidesBottomBarWhenPushed = NO;
              }
              [super pushViewController:viewController animated:animated];
          }
          
          - (UIViewController *) popViewControllerAnimated:(BOOL)animated
          {
              if([_viewControllersWithHiddenBottomBar containsObject:self.viewControllers[self.viewControllers.count - 2]])
              {
                  [self rootViewController].hidesBottomBarWhenPushed = YES;
              }
              else
              {
                  [self rootViewController].hidesBottomBarWhenPushed = NO;
              }
              UIViewController *poppedViewController = [super popViewControllerAnimated:animated];
              [_viewControllersWithHiddenBottomBar removeObject:poppedViewController];
              return poppedViewController;
          }
          
          - (UIViewController *) rootViewController
          {
              return ((UIViewController *)self.viewControllers.firstObject);
          }
          

          我使用hidesButtomBarWhenPushed 属性来填充集合,然后在视图控制器级别重置值(因为如果任何视图控制器都设置了此属性,则它上面的所有内容也会将其隐藏)。为简单起见,我使用根视图控制器来根据集合中的值控制标签栏的显示和隐藏。

          你还需要在某处初始化集合,我刚刚使用了initWithRootViewController:

          这对我来说非常无缝,是我能想到的最简单的方法,无需接管任何现有动画并且不必处理边缘情况。

          【讨论】:

            【解决方案7】:

            这是一个困扰我一段时间的问题,我只是找到了一个可行的解决方案。 hidesBottomBarWhenPushed 属性是一种非常奇怪的野兽,在我看来,它的工作方式与直觉相反。

            它的问题是当你推送一个新的视图控制器(或弹回)时,navigationController 会询问所有个视图控制器(从上到下)是否要隐藏底部栏,如果任何他们说YES标签栏将被隐藏,这就是标签栏保持隐藏的原因尽管将NO设置为隐藏在新的视图控制器上。

            这是我的解决方案 - 覆盖视图控制器中您希望没有标签栏的 hidesBottomBarWhenPushed getter,并检查它是否位于堆栈顶部:

            目标-C

            - (BOOL) hidesBottomBarWhenPushed
            {
                return (self.navigationController.topViewController == self);
            }
            

            Swift(不是那么明显,因此是 sn-p)

            override var hidesBottomBarWhenPushed: Bool {
                get {
                    return navigationController?.topViewController == self
                }
                set {
                    super.hidesBottomBarWhenPushed = newValue
                }
            }
            

            这很好地将隐藏/显示逻辑封装在一个地方,因此您不必在执行隐藏的视图控制器之外考虑它。

            【讨论】:

            • 很好的答案!我认为它给出了每个人都期望的结果。应该允许每个视图控制器选择是否需要底部栏。
            • 非常感谢,你让我很开心,这让我快疯了 :) 这是智障,它应该开箱即用,至少我猜这是每个人都期望的行为。
            • 这很棒而且很简单。我认为 Apple 应该将这种行为作为一个选项添加。
            【解决方案8】:

            我遇到了同样的问题,但 3 小时后我找到了解决方案! 在这个话题answered Oct 8 '10,Dave Batton 说:

            hidesBottomBarWhenPushed 属性的正确使用方法是:

            self.anotherViewController.hidesBottomBarWhenPushed = YES;
            [self.navigationController pushViewController:self.anotherViewController animated:animated];
            

            【讨论】:

              【解决方案9】:

              设置视图控制器

              我不需要在标签栏中设置屏幕,过去两种方法中的设置屏幕和设置屏幕在显示底部Tabbar中推送任何屏幕。

              override func viewWillAppear(_ animated: Bool) {
              
                   self.hidesBottomBarWhenPushed = true
              }
              
              override func viewDidAppear(_ animated: Bool) {
              
                  self.hidesBottomBarWhenPushed = false
              }
              

              谢谢,如果您有任何疑问,请随时询问。

              【讨论】:

                猜你喜欢
                • 2021-07-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-12-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多