Navigation Controller + UIToolbar

In this tutorial we will learn how to add a UIToolbar to an app with UINavigationController.
In this tutorial we will learn how to add a UIToolbar to an app with UINavigationController. I had a requirement where I wanted to add a UIToolbar with one button. Clicking the button will load a view controller which is the same view controller when a UITableViewCell is selected and this is what I did.

This is how the final app will look like


Start by creating a new project by selecting “Navigation-Based Application”. Open the header file of “RootViewController” and create a variable of type UIToolbar and UINavigationController. This is how the file should look like, without the comments. We also create two variables of the same UIViewController and this will be explained later.

#import <UIKit/UIKit.h>

@class InfoViewController;

@interface RootViewController : UITableViewController {

UIToolbar *toolbar;
InfoViewController *ivControllerToolbar;
InfoViewController *ivControllerCell;
UINavigationController *infoNavController;
}

@end

Open the implementation file and write the following code in viewWillAppear method. This is the method which is always called when the view is going to appear.

– (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];

//Initialize the toolbar
toolbar = [[UIToolbar alloc] init];
toolbar.barStyle = UIBarStyleDefault;

//Set the toolbar to fit the width of the app.
[toolbar sizeToFit];

//Caclulate the height of the toolbar
CGFloat toolbarHeight = [toolbar frame].size.height;

//Get the bounds of the parent view
CGRect rootViewBounds = self.parentViewController.view.bounds;

//Get the height of the parent view.
CGFloat rootViewHeight = CGRectGetHeight(rootViewBounds);

//Get the width of the parent view,
CGFloat rootViewWidth = CGRectGetWidth(rootViewBounds);

//Create a rectangle for the toolbar
CGRect rectArea = CGRectMake(0, rootViewHeight – toolbarHeight, rootViewWidth, toolbarHeight);

//Reposition and resize the receiver
[toolbar setFrame:rectArea];

//Create a button
UIBarButtonItem *infoButton = [[UIBarButtonItem alloc]
initWithTitle:@”Info” style:UIBarButtonItemStyleBordered target:self action:@selector(info_clicked:)];

[toolbar setItems:[NSArray arrayWithObjects:infoButton,nil]];

//Add the toolbar as a subview to the navigation controller.
[self.navigationController.view addSubview:toolbar];

//Reload the table view
[self.tableView reloadData];

}

Start by initializing the toolbar and then calculate some values. These values determine the position and the width/height of the toolbar. A button is created which will be added to the the toolbar and when the button is clicked “info_cancel” method is called. The button are added from LTR. The toolbar is then added as a subview to the navigation controller.

Add a new view using IB and I have named it “InfoView”. Create a UIViewController in XCode and name it InfoViewController and assign this class as the class to be used by the InfoView nib file. Declare a Boolean property in InfoViewController called “isViewPushed” which will be true when a view is pushed to the top of the stack and false when the view is presented as a modal view. Based on the value of this variable we add a cancel button when the view is loaded as a modal view.

This is how the info button will look like when clicked

– (void) info_clicked:(id)sender {

//Initialize the Info View Controller
if(ivControllerToolbar == nil)
ivControllerToolbar = [[InfoViewController alloc] initWithNibName:@”InfoView” bundle:[NSBundle mainBundle]];

ivControllerToolbar.isViewPushed = NO;

//Initialize the navigation controller with the info view controller
if(infoNavController == nil)
infoNavController = [[UINavigationController alloc] initWithRootViewController:ivControllerToolbar];

//Present the navigation controller.
[self.navigationController presentModalViewController:infoNavController animated:YES];

}

From the header file we know that we have declared two types of ViewControllers for the same nib file, this is because for some reason having one variable to control the same view controller results in some unexpected behavior. When the info button is clicked we first initialize the ivControllerToolbar, then we initialize the infoNavController with the ivControllerToolbar view controller. Finally, we present the infoNavController using “presentModalViewController” method of the navigationController. If we do not do this, then the infoview will be loaded without a navigation controller and we will have no graceful way of getting back to the RootViewController. Also, notice that we tell the infoviewcontroller explicitly that the controller is not pushed. This variable will be used in viewDidLoad method of the InfoViewController.

if(isViewPushed == NO) {

self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:@selector(cancel_Clicked:)] autorelease];
}

Here we check if the view is pushed it is only then we add the cancel button to the left bar button item. When the button is clicked “cancel_Clicked” method is called which will dismiss the modal view presented. This is how the code looks like

-(void) cancel_Clicked:(id)sender {

[self.navigationController dismissModalViewControllerAnimated:YES];
}

Since, this is a table view a user can select a row and go to its detail view. We have some sample and this is how the didSelectRowAtIndexPath method will look like.

– (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic — create and push a new view controller

//Initialize the info view controller.
if(ivControllerCell == nil)
ivControllerCell = [[InfoViewController alloc] initWithNibName:@”InfoView” bundle:[NSBundle mainBundle]];

ivControllerCell.isViewPushed = YES;

//Push the view controller to the top of the stack.
[self.navigationController pushViewController:ivControllerCell animated:YES];
}

First we initialize the info view controller called “ivControllerCell” which is specifically used to load the same view controller in didSelectRowAtIndexPath method. This time we tell the info view controller that the view will be pushed to the top of the stack.

This is the easiest way I found to add a UIToolbar to an application with UINavigationController. You can download the source code here and please leave me your comments.

Happy Programming
iPhone SDK Articles