views:

775

answers:

4

I've got an iPhone application with a UITableView menu. When a row in the table is selected, the appropriate view controller is pushed onto the application's UINavigationController stack.

My issue is that the MenuViewController does not need a toolbar, but the UIViewControllers which are pushed onto the stack do. Each UIViewController that gets pushed calls setToolbarHidden:animated: in viewDidAppear:. To hide the toolbar, I call setToolbarHidden:animated: in viewWillDisappear:.

Showing the toolbar works, such that when the pushed view appears the toolbar slides up and the view resizes correctly. However, when the back button is pressed the toolbar slides down but the view does not resize. This means that there's a black strip along the bottom of the view as the other view transitions in. I've tried adding the toolbar's height to the height of the view prior to hiding the toolbar, but this causes the view to be animated during the transition so that there's still a black bar.

I realise I can manage my own UIToolbar, but I'd like to use UINavigationControllers built in UIToolbar for convenience.

This forum post mentions the same issue, but no workaround is mentioned.

A: 

This is just a wild stab in the dark but maybe you should let the runloop run once after hiding the toolbar:

[viewController setToolbarHidden:YES animated:YES];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]];
Diederik Hoogenboom
Nope, that makes no difference.
Nathan de Vries
Bummer. It was worth a try.
Diederik Hoogenboom
A: 

I too have experienced this problem. In my case, the only way I found to successfully hide the toolbar without showing the background of the window is to call [self.navigationController setToolbarHidden:YES animated:animated] in your view controller’s -viewDidAppear: method.

Jeff Kelley
A: 

I had the same problem and here is the solution that worked for me. Say you're pushing SomeUIViewController onto your navigation stack.

Define this (private) ivar in the interface of SomeUIViewController:

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

Implement the following methods of 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];
}

The idea is that you want to hide the toolbar owned by the navigation controller after SomeUIViewController's view has disappeared. This way, you avoid any unwanted display artifacts.

DISCLAIMER

This is merely an answer that shows a workaround solution for the stated question. It is meant solely to point out a detail of the inner workings of the framework. It is also meant as an example of what not to submit to the Apple AppStore.

octy
A: 

Try implementing a UINavigationControllerDelegate and setting it to your navigation controller's delegate property. This achieved for me what you are describing in your post, with no visible artifacts.

The following code assumes that secondController is pushed into the navigation view by an action performed in the 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 is just a helper method:

AppDelegate_Shared.m

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