在viewWillDisappear期间隐藏UINavigationController的UIToolbar:

时间:2010-02-26 05:45:01

标签: iphone cocoa-touch uikit uinavigationcontroller uitoolbar

我有一个带有UITableView菜单的iPhone应用程序。当选择表中的行时,相应的视图控制器将被推送到应用程序的UINavigationController堆栈。

我的问题是MenuViewController不需要工具栏,但推送到堆栈的UIViewControllers可以。推送的每个UIViewController都会在setToolbarHidden:animated:中调用viewDidAppear:。要隐藏工具栏,我在setToolbarHidden:animated:中调用viewWillDisappear:

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

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

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

11 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:6)

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

答案我解决了我的问题。它也可能对你有用(虽然这个问题已经很老了,但我认为这可能会帮助像我这样读过这篇文章的人六次寻找暗示。)

这就是我的所作所为。我不知道标记协议是否是惯用的目标-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的应用程序:didFinishLaunchingWithOptions:方法中,我像这样连接代理:

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

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

答案 2 :(得分:5)

对于推送时不需要工具栏的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];

答案 3 :(得分:1)

尝试实现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];
}

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:1)

这里的问题是设置了UITableView的框架,使其不与UIToolbar重叠。也就是说,它位于UIToolbar的正上方。当您将下一个UIViewController推送到UINavigationController堆栈,同时移除UIToolbar时,除了您放置的内容之外,没有任何内容可以显示,但{strong}背后的UIWindow在它的位置。

转换后没有笨拙动画的一种解决方法是将UITableView置于与常规视图共享同一帧的UIView“容器”中,但将UIToolbarUIViewController重叠您希望在过渡期间看到的所需颜色(例如白色)。

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

通过编写自定义UITableViewController并使用该UIView代替UITableView,或者偷偷摸摸地在{{{{{}下方插入新的UITableViewController“容器”,可以使这更加优雅1}}在您现有的{{1}}。

答案 6 :(得分:0)

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

self.navigationController.toolbar.barStyle = UIBarStyleBlackTranslucent;
在viewDidLoad中

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

答案 7 :(得分:0)

我同意杰夫的回答。但是如果我在viewController的-viewDidAppear方法中隐藏工具栏,通过它会推送不同的viewControllers,就会出现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];
.
.
.
}

答案 8 :(得分:0)

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

我遵循这条规则取得了成功:

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

这样,每个视图控制器都以正确的工具栏状态启动,并且您不必担心在取消视图控制器时“恢复”工具栏状态。

答案 9 :(得分:-2)

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

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

答案 10 :(得分:-3)

我遇到了同样的问题,这是适合我的解决方案。假设您正在将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的视图消失后隐藏导航控制器所拥有的工具栏。这样,您可以避免任何不需要的显示瑕疵。

<强>声明

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