In my iPhone application I am using UITabbarController + UINavigationController, created in appDelegate.
My issue is as follows:
On screen- I have tableview. When one selects cell I am pushing the controller to screen-B. Now without poping it if I select another tab from tabbar, then view gets refreshed but navigationbar is not getting refreshed. It displays navigationbar of screen-Bscreen-B.
Used below code but nothing seems to solve my issue:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[UINavigationController class]])
{
[viewController.navigationController popToRootViewControllerAnimated:NO];
}
}
try this in appdelegate
UINavigationController *screen1=[[UINavigationController alloc] initWithRootViewController:controller1];
UINavigationController *Bscreen=[[UINavigationController alloc] initWithRootViewController:controller2];
NSArray *tabbararray=[[NSArray alloc] initWithObjects: screen1,Bscreen,nil];
self.TabControllerObj.viewControllers=allviewcontrollers;
and make tabbar as root viewcontroller of your window
I've created the following storyboard:
Navigation Controller
Login View Controller
Tab Controller
Navigation Controller
Search View Controller
Results View Controller
Detail View Controller
Navigation Controller
Advanced Search View Controller
Results View Controller
Detail View Controller
When the user taps a tab bar button I want to make sure that the view they see is the Search (if they tapped Search) or Advanced Search (if they tapped Advanced) not the point in the stack they might have previously been on for a given tab. In other words, I want to have them start at the top/root view
I've set the tab bar's delegate to a class and implemented the didSelectViewController as:
Tab bar controller .h
#import <UIKit /UIKit.h>
#interface TabController : UITabBarController <UITabBarControllerDelegate>
#end
Tab bar controller .m
- (void) viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
[viewController.navigationController popToRootViewControllerAnimated:YES];
}
In both the Search and Advanced Search Controller .m
- (void) viewWillAppear
{
[super viewWillAppear:animated];
//Hide the nav bar at the search/advanced controller level. Will be shown at results and detail levels
[[self navigationController] setNavigationBarHidden:YES animated:YES];
//Set the text for the back button
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle: #"title" style: UIBarButtonItemStyleBordered target: nil action: nil];
[self.navigationItem setBackBarButtonItem: backButton];
}
The result is that when the user taps the Advanced Search button nothing appears but a black screen. Comment out that code and the Advanced Search is properly displayed.
Note that the Results and Detail Controllers are reused for both the search and advanced searches.
Any ideas? Thanks for your help. If a keep banging my head against this wall I won't have to buy a halloween costume!
I had same kind of issue. I have used this code and it worked.[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
I want to add a global right bar button in the global AppDelegate so all my view controllers will have this button automatically.
I added in the AppDelegate
navigator.window.rootViewController.navigationController.navigationItem.rightBarButtonItem
= [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Test", #"")
style:UIBarButtonItemStyleBordered target:self action:#selector(showTest)] autorelease];
Of course the above code is not working..any problem with the code above?
Well, I'm not sure you can do it in your way, because UINavigatorController always uses the buttons from the view controller that is currently displayed, and not from the top / root controller.
What you can do is to subclass TTViewController with a new view controller and set your left bar button item.
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#implementation BaseViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UIViewController
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Test", #"")
style:UIBarButtonItemStyleBordered target:self action:#selector(showTest)] autorelease];
}
and then you should extend all your view controllers from this base controller, which contains the right navigation bar item
What you need to do is to tap into the navigation controller you wish to hook into. then you can implement UINavigationControllerDelegate (each navigation controller has a delegate property) which will give you these events:
// Called when the navigation controller shows a new top view controller via a push, pop or setting of the view controller stack.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
You can implement
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
and put your right button in place.
I'm presenting a modal view controller in a UISplitViewController based app. I've swapped the default detail view for a UINavigationController.
In my UINavigationController, I've implemented some methods to show the "Master" button for the split view controller in the top left. The problem is that when the device orientation changes while the modal view is visible, the button does not disappear from the main view in my navigation controller.
What could be causing this issue?
EDIT:
I've moved the template logic for the button into a subclass of UINavigationController. The problem is that when the visibleViewController presents a modalViewcontroller, it becomes the visibleViewController. So, my code won't correctly remove the button for some reason. Here's my code:
Code:
#pragma mark - Split view support
- (void)splitViewController:(UISplitViewController *)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController: (UIPopoverController *)pc{
barButtonItem.title = NSLocalizedString(#"Menu", #"");
//
// TODO: Handle cases where there is
// a modal view controller that is
// being shown to the user.
//
[((UIViewController *)[self.viewControllers objectAtIndex:0]).navigationItem setLeftBarButtonItem:barButtonItem];
self.popoverController = pc;
}
// Called when the view is shown again in the split view, invalidating the button and popover controller.
- (void)splitViewController:(UISplitViewController *)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem{
[self.visibleViewController.navigationItem setLeftBarButtonItem:nil];
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
//
// Preserve navigation items across detail
// view loads in portrait mode.
//
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated{
UIBarButtonItem *barItem = nil;
if (self.visibleViewController.navigationItem.leftBarButtonItem != nil) {
barItem = self.visibleViewController.navigationItem.leftBarButtonItem;
}
[super setViewControllers:viewControllers animated:animated];
if (barItem != nil) {
[self.visibleViewController.navigationItem setLeftBarButtonItem:barItem];
}
}
I don't think it's possible to use SplitViewController and display the button for the master view in a navigationItem. The UISplitViewControllerDelegate is specifically designed to work with a UIBarButtonItem, you'll probably have to implement a custom popover controller to get that to work.
I'm using the ABPeoplePickerNavigationController, a subclass of UINavigationController, and in the context I'm using it the default nav bar button for the right side, "Cancel", makes no sense. I can't find a way to disable or hide it, and whatever method used needs to be public and store-approvable.
Getting rid of the nav bar entirely (picker.navigationBarHidden = YES;) might be an option except that after popping back to the list of contacts the nav bar reappears.
Subclassing ABPeoplePickerNavigationController and intercepting viewWillAppear to try and nil the cancel button did not work.
[picker setAllowsCancel:NO]; DOES work but is undocumented so I expect would never pass approval.
this one
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
UIView *custom = [[UIView alloc] initWithFrame:CGRectMake(0.0f,0.0f,0.0f,0.0f)];
UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithCustomView:custom];
//UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addAction)];
[viewController.navigationItem setRightBarButtonItem:btn animated:NO];
[btn release];
[custom release];
}
works perfect!
The examples herein using the delegate method navigationController:willShowViewController:animated: do work, but it may be the case that you want to add your own navigation item in your own controllers and the given options will remove anything that you might set in your own controllers. Here's code that I've successfully used to get this option to work well:
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
// Here we want to remove the 'Cancel' button, but only if we're showing
// either of the ABPeoplePickerNavigationController's top two controllers
if ([navigationController.viewControllers indexOfObject:viewController] <= 1) {
viewController.navigationItem.rightBarButtonItem = nil;
}
}
Note that there are two view controllers in the navigation controller's stack, the one for contact groups and one for the contact list. This is why we cannot just check fi the viewController is the navigation controller's top view controller.
There is no answer to this - write a new person picker if you can't live with the cancel.
You can achieve that result browsing through the picker subviews. Just a little boring...
I haven't tried it yet, but I think Uby is saying to iterate through the subviews of the picker until you find one that is isKindOfClass:[UIBarButtonItem class] and then you can change it's title property. It might also be in the navigationBar's 'Item' array.
Set delegate to PeoplePickerController controller.
In the delegate class, have this delegate method.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIView *pCustomView = [[UIView alloc] initWithFrame:CGRectMake(0,0,0,0)];
UIBarButtonItem *pBtn = [[UIBarButtonItem alloc] initWithCustomView:pCustomView];
[viewController.navigationItem setRightBarButtonItem:pBtn animated:NO];
[pBtn release];
[pCustomView release];
}
Be sure to set the delegate for picker object (not the peoplePickerDelegate, just the delegate) to the class that implement the following method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
UIView *custom = [[UIView alloc] initWithFrame:CGRectMake(0,0,0,0)];
UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithCustomView:custom];
[viewController.navigationItem setRightBarButtonItem:btn animated:NO];
[btn release];
[custom release];
}
It works fine but in iOS 4 there is one more thing. When I switch back to my app using Fast App Switching feature, the cancel button appears again.
The method
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
doesn't get called. So I made this:
- (void)applicationDidEnterBackground:(UIApplication *)application {
id topView = pickerControllerDelegate.peoplePicker.topViewController;
topView.navigationItem.rightBarButtonItem = nil;
}
It works pretty well.
according to russel b you could just overwrite your viewdidapper
this worked for me:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UINavigationItem *item = (UINavigationItem *)[self.navigationBar.items lastObject];
item.rightBarButtonItems = [[NSArray alloc] init];
item.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addPerson)];
}
EDIT: See comments below. This is now an illustration of what not to do.
I tried to get the desired behavior with the public API by subclassing ABPeoplePickerNavigationController and intercepting all the events that change the current navigation view controller view. Then one can just navigate the view hierarchy and purge all the unwanted buttons.
You can navigate the view hierarchy from a delegate, but you aren't privy to the events that change the view state... which makes it hard to kill the Cancel button and make it stick.
This code kind of worked for me (NOTE: it brute-force kills all the right-hand buttons):
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self killCancelButton];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self killCancelButton];
}
- (UIViewController*)popViewControllerAnimated:(BOOL)animated {
UIViewController *result = [super popViewControllerAnimated:animated];
[self killCancelButton];
return result;
}
- (void)killCancelButton {
for (NSUInteger itemIdx = 0; itemIdx < self.navigationBar.items.count; itemIdx++) {
UINavigationItem *item = [self.navigationBar.items objectAtIndex:itemIdx];
item.rightBarButtonItems = [[NSArray alloc] init];
}
}