【问题标题】:Hiding a UINavigationController's UIToolbar during viewWillDisappear:在 viewWillDisappear 期间隐藏 UINavigationController 的 UIToolbar:
【发布时间】:2011-01-21 08:03:05
【问题描述】:

我有一个带有UITableView 菜单的iPhone 应用程序。 When a row in the table is selected, the appropriate view controller is pushed onto the application's UINavigationController stack.

我的问题是MenuViewController 不需要工具栏,但被推入堆栈的UIViewControllers 需要。每个被推送的UIViewControllerviewDidAppear: 中调用setToolbarHidden:animated:。要隐藏工具栏,我在viewWillDisappear: 中调用setToolbarHidden:animated:

显示工具栏有效,这样当推送的视图出现时,工具栏会向上滑动并且视图会正确调整大小。但是,当按下后退按钮时,工具栏会向下滑动,但视图不会调整大小。这意味着当另一个视图过渡时,视图底部有一条黑色条带。我尝试在隐藏工具栏之前将工具栏的高度添加到视图的高度,但这会导致视图在过渡,以便仍然有一个黑条。

我意识到我可以管理自己的 UIToolbar,但为了方便,我想使用 UIToolbar 中内置的UINavigationControllers

This forum post 提到了同样的问题,但没有提到解决方法。

【问题讨论】:

    标签: iphone cocoa-touch uikit uinavigationcontroller uitoolbar


    【解决方案1】:

    我也遇到过这个问题。就我而言,我发现在不显示窗口背景的情况下成功隐藏工具栏的唯一方法是在视图控制器的 -viewDidAppear: 方法中调用 [self.navigationController setToolbarHidden:YES animated:animated]

    【讨论】:

    • 赞成。这是唯一没有背景渗透的解决方案。工具栏会出现“柴郡猫”消失——即它在新视图到位后而不是之前消失——但它比让背景渗出要好得多。
    • 如此简单。很简单。 (虽然我宁愿在过渡期间隐藏它。)
    • 看起来 ... animated:animated 部分在这里很有意义 - 即使在 -viewWillAppear: 方法中也有效。
    【解决方案2】:

    我对这个问题的答案不满意,所以我发布了自己的答案:Reference to source view controller and destination view controller at the same time

    我得到的答案解决了我的问题。它也可能适用于您的问题(尽管这个问题已经很老了,但我认为这可能会帮助像我这样阅读这篇文章六遍寻找提示的人)。

    这就是我所做的。我不知道标记协议是否是惯用的objective-c,但我将它们比作我在c#中使用的属性,所以我有这个标记协议:

    @protocol HidesNavigationItem
    @end
    

    我将 UINavigationControllerDelegate 添加到我的 AppDelegate。我还不确定这是否是一件好事。我曾考虑将该实现保留在另一个对象中,但现在,这就是我放置它的地方。这是实现:

    #pragma mark Navigation Controller Delegate
    -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        [navigationController setNavigationBarHidden:[viewController conformsToProtocol:@protocol(HidesNavigationItem)] animated:animated];
    }
    

    这样,我可以像这样在 UIViewController 实现上设置我的标记协议:

    @interface MyViewController : UIViewController <HidesNavigationItem>
    

    如果我没有那个界面,它会把它放回去。

    最后,在我的 appDelegate 的 application:didFinishLaunchingWithOptions: 方法中,我像这样连接代理:

    if ([self.window.rootViewController isMemberOfClass:[UINavigationController class]])
        ((UINavigationController*)self.window.rootViewController).delegate = self;
    

    现在我没有黑匣子,也没有柴郡猫。我的解决方案当然是关于导航栏,但我确信它对工具栏同样有效。这与 Danra 的回答非常相似,只是我得到了没有“动画:动画”的黑盒子。

    【讨论】:

    • 我仍然使用这种技术得到一个黑条。
    【解决方案3】:

    对于在推送时不需要工具栏的 UIViewController 可以考虑使用任一

    为那个 UIViewController 实现 hidesBottomBarWhenPushed 方法:

    // method to be added to the UIViewController that has no toolbar
    - (BOOL) hidesBottomBarWhenPushed {
        return YES;
    }
    

    或者在推入 UIViewController 之前,设置 hidesBottomBarWhenPushed 的值:

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

    【讨论】:

      【解决方案4】:

      尝试实现 UINavigationControllerDelegate 并将其设置为导航控制器的委托属性。 这对我来说实现了您在帖子中描述的内容,没有可见的伪影。

      以下代码假设 secondController 通过在 firstController 中执行的操作被推送到导航视图中。

      MyNavigationControllerDelegate.h

      @interface MyNavigationControllerDelegate : NSObject<UINavigationControllerDelegate> {
      }
      
      -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
      -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
      
      @end
      

      MyNavigationControllerDelegate.m

      #import "MyNavigationControllerDelegate.h"
      #import "AppDelegate_Shared.h"
      
      @implementation MyNavigationControllerDelegate
      
      -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
          if ([AppDelegate_Shared sharedDelegate].firstController  == viewController ) {
              [navigationController setNavigationBarHidden:TRUE];
              [navigationController setToolbarHidden:FALSE];
          }
      }
      
      -(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
          if ([AppDelegate_Shared sharedDelegate].secondController == viewController ) {
              [navigationController setNavigationBarHidden:FALSE];
              [navigationController setToolbarHidden:TRUE];
          }
      }
      
      @end
      

      sharedDelegate 只是一个辅助方法:

      AppDelegate_Shared.m

      + (AppDelegate_Shared*)sharedDelegate {
          return (AppDelegate_Shared*)[[UIApplication sharedApplication] delegate];
      }
      

      【讨论】:

        【解决方案5】:

        要在新视图控制器中显示工具栏,只需添加以下内容:

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

        隐藏工具栏:

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

        在屏幕之间移动时,使用以下代码推送新的视图控制器:

        SettingsRecordingViewController *vc = [[SettingsRecordingViewController alloc] initWithNibName:@"SettingsRecordingViewController" bundle:[NSBundle mainBundle]]; 
        [self.navigationController pushViewController:vc animated:YES];      
        [vc release];
        

        如果它具有不同的工具栏状态(隐藏/显示),则会显示隐藏/显示工具栏的漂亮动画。

        【讨论】:

          【解决方案6】:

          这里的问题是UITableView 的框架设置为不与UIToolbar 重叠。也就是说,它位于UIToolbar 的正上方。当您将下一个 UIViewController 推送到 UINavigationController 堆栈时,同时删除 UIToolbar,除了后面的 UIWindow 之外,没有什么可显示的,除非您在其位置放一些东西 .

          过渡后没有尴尬动画的一种解决方法是将UITableView 放置在与常规视图共享同一帧的UIView“容器”中,但在UIToolbar 下方使用您希望的所需颜色在过渡期间看到(例如白色)。

          要制定underlap,您可以将UIViewController 设置为wantsFullScreenLayout = YES。然后,您将确保您的 UITableView 具有与使用容器之前相同的框架。即它位于导航栏下方,工具栏上方。

          通过编写自定义 UIViewController 并使用它而不是 UITableViewController,或者偷偷地将新的 UIView“容器”插入到现有的 UITableView 下方的 @987654338 中,这可以变得更加优雅@。

          【讨论】:

            【解决方案7】:

            我使用自定义背景图像作为工具栏背景,使用自定义图像作为表格背景。当视图从另一个表视图来回转换时,我在底部的黑条上遇到了同样的问题。但是我设置了

            self.navigationController.toolbar.barStyle = UIBarStyleBlackTranslucent;
            

            在 viewDidLoad 中。

            这会将背景图像设置为背景的全部潜在大小,如果您有一个透明的工具栏,这将是有意义的。当您使用标准的不透明工具栏时,这可能不是一个好的解决方法,但对于那些自定义工具栏的人来说,您可以两全其美。

            【讨论】:

              【解决方案8】:

              我同意 Jeff 的回答。但是,如果我在 viewController 的 -viewDidAppear 方法中隐藏工具栏,通过该方法推送不同的 viewController,则会出现 UI 故障。

              为了避免这种情况,我进行了实验,发现在 -viewWillAppear 调用中调用 -setToolbarHidden 确实隐藏了工具栏,但正如问题所述,虽然展开的视图不会被 tableview 行占用。

              为了解决这个问题,我已更改为以下代码,现在它可以正常工作了:

              - (void)viewDidLoad
              {
                  [super viewDidLoad];
              .
              .
              .
                  [self reframeRowHeight];
                  [self.menuItemTableView addObserver:self
                                           forKeyPath:@"frame"
                                              options:NSKeyValueObservingOptionNew
                                              context:nil];
                  [self.menuItemTableView setBounces:NO];
              .
              .
              .
              }
              -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
              {
                  if ([keyPath isEqualToString:@"frame"])
                  {
                      [self reframeRowHeight];
                  }
              }
              
              -(void)reframeRowHeight
              {
              
                  [self.menuItemTableView setRowHeight:self.menuItemTableView.frame.size.height/self.menuItems.count];
                  [self.menuItemTableView reloadData];
              }
              
              - (void)viewWillAppear:(BOOL)animated
              {
                  [super viewWillAppear:animated];
              .
              .
              .
                  // Bad Apple! - http://stackoverflow.com/questions/2339721/hiding-a-uinavigationcontrollers-uitoolbar-during-viewwilldisappear
                  [self.navigationController setToolbarHidden:YES animated:YES];
              .
              .
              .
              }
              

              【讨论】:

                【解决方案9】:

                管理工具栏状态(即哪个 VC 需要/不需要工具栏)很快就会变得棘手。

                我已经成功地遵守了这条规则:

                对于每个视图控制器,在viewWillAppear() 中,决定它是否需要工具栏,然后分别调用navigationController?.setToolbarHidden(true or false, animated: animated)

                这样,每个视图控制器都以正确的工具栏状态开始,您不必担心在视图控制器关闭时“恢复”工具栏状态。

                【讨论】:

                  【解决方案10】:

                  这只是在黑暗中的一次野刺,但也许你应该在隐藏工具栏后让 runloop 运行一次:

                  [viewController setToolbarHidden:YES animated:YES];
                  [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]];
                  

                  【讨论】:

                  • 不,没有区别。
                  【解决方案11】:

                  我遇到了同样的问题,这是对我有用的解决方案。假设您将 SomeUIViewController 推送到导航堆栈。

                  SomeUIViewController的接口中定义这个(私有)ivar:

                  // keep a reference to the navigation controller for use in viewDidDisappear:(BOOL)animated method
                  UINavigationController * _navigationController; 
                  

                  实现SomeUIViewController的以下方法:

                  - (void)viewWillDisappear:(BOOL)animated {
                      [super viewWillDisappear:animated];
                      // here, your controller still has a reference to self.navigationController
                      _navigationController = [self.navigationController retain];
                  }
                  
                  - (void)viewDidDisappear:(BOOL)animated {
                      // at this point, self.navigationController = 0x0, so
                      // use your retained reference to the navigation controller to perform any last minute operations, then release
                  
                      [_navigationController setToolbarHidden:YES];
                      [_navigationController release];
                  
                      [super viewDidDisappear:animated];
                  }
                  

                  这个想法是你想隐藏导航控制器拥有的工具栏SomeUIViewController的视图消失了。这样,您就可以避免任何不需要的显示伪影。

                  免责声明

                  这只是一个答案,显示了所述问题的变通解决方案。它只是为了指出框架内部工作的细节。这也是一个提交到 Apple AppStore 的示例。

                  【讨论】:

                    猜你喜欢
                    • 2013-12-17
                    • 2011-02-27
                    • 2012-05-13
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-03-24
                    • 2016-01-24
                    • 2010-09-22
                    • 1970-01-01
                    相关资源
                    最近更新 更多