Skip to content


Adding any kinds of UI elements into a UINavigationBar

In iCab Mobile and many other iPhone apps you can see a toolbar with buttons, text fields and other UI elements at the top of the screen. And this toolbar looks like a UINavigationBar object. But if you try to add UI elements into a UINavigationBar object in Interface Builder, you’ll notice that you can’t add all UI elements in any location within the UINavigationBar. More concrete: you can add up to three elements in concrete spots (left, middle, right), and only certain UI elements. A UINavigationBar object is meant to be used for navigation purposes and therefore is usually automatically populated by a UINavigationController. And the UINavigationController only uses the three spots (left to go back to the previous navigation level, the center area to display the title and the right to add an “edit” button for example).

So how are iCab Mobile and other apps able to populate a UINavigationBar object with any UI elements in other than the three available spots?

First of all, not everything which looks like a UINavigationBar is a UINavigationBar. Up to iCab Mobile 1.7 the toolbar at the top of the screen is not a UINavigationBar object, it’s a UIImageView object with an image that looks like a UINavigationBar would look like. But since iCab Mobile 2.0 it will be a UINavigationBar. iCab Mobile 2.0 will allow to customize the colors of the toolbars, and unlike images, the UINavigationBar object can have any color.

But even for UIImageView objects, you can’t add any subviews in Interface Builder. So the main question is the same: how to add any available UI elements in any location as subview of these objects (it doesn’t matter if these objects are UIImageView or UINavigationBar objects)?

The answer is simple: you have to do this programatically. UIImageView and UINavigationBar are both subclasses of UIView. And UIView objects can have subviews. You only need to call the method addSubview: to add a subview. When using UINavigationBar as the root for our toolbar, we only have to make sure that it is not managed by a UINavigationController. But because we need to create all the objects programmatically, this isn’t a problem at all.

One place to create the toolbar can be the viewDidLoad method of the UIViewController which serves as the controller for the view that holds the toolbar. The following code is an example how this would look like. All the code fragments should go into the viewDidLoad method, I’ve split the code into fragments only because it’s easier to explain what I’m doing this way.

- (void)viewDidLoad
{
  [super viewDidLoad];

  CGFloat width = self.view.frame.size.width;

Here we first get the width of the view of our UIViewController. It is used to calculate the widths of all of the toolbar elements.

  UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:
                                           CGRectMake(0,0,width,52)];
  navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  [self.view addSubview:navBar];
  [navBar release];

This fragment creates the UINavigationBar element and we add it as subview to the view object of our UIViewController. If the application should support the autorotation feature, we have to make sure that the width is flexible and set the autoresizing mask accordingly.

  UILabel *label = [[UILabel alloc] initWithFrame:
                                   CGRectMake(10,2,width-20,14)];
  label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  label.text = @"some text for the title...";
  label.backgroundColor = [UIColor clearColor];
  label.font = [UIFont systemFontOfSize:12];
  label.textAlignment = UITextAlignmentCenter;
  [navBar addSubview:label];
  [label release];

Then we create the title line of our toolbar. We use a UILabel element. The width must be flexible as well when the autorotation feature is supported. The label is added as a subview of the UINavigationBar object so that there is a small margin at the top, left and right side. It is important to set the background color to “clearColor” to make the background completely transparent. The default background color would be white.

  UITextField *textField = [[UITextField alloc] initWithFrame:
                                CGRectMake(10,19,width-80,26)];
  textField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  textField.borderStyle = UITextBorderStyleRoundedRect;
  textField.font = [UIFont systemFontOfSize:17];
  [navBar addSubview:textField];
  [textField release];

This fragment will add a text field to enter some text into the toolbar. This is similar to what we’ve done to add the label.

  UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [button setFrame:CGRectMake(width-60,19,50,26)];
  [button setTitle:@"Go" forState:UIControlStateNormal];
  button.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
  [navBar addSubview:button];
}

And finally we’ve added a button to the toolbar. Nothing special here. This time the autoresizing mask is set to have a flexible left margin, because the button should always have the same width. It only should be placed on the right side of the toolbar, so the right margin must be fixed, while the left must be flexible.

This is more or less all you need to do to add UI elements in UINavigationBar objects. Of course you also need to set the delegates for some of the UI elements in order to process clicks on the button or text field editing.

This is how the toolbar from above will look like:

Posted in iPhone & iPod Touch, Programming.

Tagged with , , .


17 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Techno says

    Great help ! Keep up. thanks.

  2. Patty says

    That’s not a lot of code????

    How would we do something this simple… all in IB?
    4 buttons… but looks like they are on navigation bar?

  3. Daniel says

    If you don’t need a NavigationBar’s back button, why not just do it all in IB with a toolbar as your base? Toolbars don’t just have to go on the bottom of the view.

  4. Alexander Alexander says

    Yes, since OS 3.2 you can also place the toolbars at the top of the screen. But at the time I wrote this article, OS 3.2 was not available and it was not possible to place a UIToolbar at the top of three screen without some visual glitches.

  5. Thomas says

    Thanks dude, I’m both iphone designer / developer and I wanted red buttons on a black nav bar.. combined with this tutorial http://www.switchonthecode.com/tutorials/iphone-tutorial-how-to-create-a-blue-navigation-button you helped me out!

    Keep it up!

  6. Kartik Thapar says

    Hi Alexander

    I am trying to create a uinavigation bar which is quite similar to the one we find in safari (iPad). The issue is that I am not able to add uibarbuttonitems to the navigation bar. The navigation bar would be more than 44 pixel.

    Can you please explain, how you added those uibarbuttonitems (bookmarks,etc) to the navigationbar in iCab?

    Thanks very much.

  7. Alexander Alexander says

    @Kartik Thapar

    In iCab Mobile the toolbar is just a normal UIView with a background image. And the buttons are standard UIButtons.

    But even if you’re using a navigation toolbar (which is also just a UIView), you have to add normal buttons (as subviews) instead of UIBarButtonItems if you need more than just two buttons in the toolbar. A navigation toolbar accepts only two UIBarButtonItems at certain locations. And because a UIBarButtonItem is not a UIView, you can’t add them as subviews as normal UIViews.

  8. Kartik Thapar says

    Thanks Alexander. Much help.

    Would it be possible for you to pass me those button images? I am looking out for the search button, actions button and organise button. I am not good at photoshop, so I cannot make them myself.

    Thanks for your help.

  9. AD says

    How do you disable buttons that you’ve added to the uinavigation bar, esp if you do it this way? Thanks

  10. Alexander Alexander says

    @AD
    Just use the standard methods for the buttons to disable them. UIButton objects (or UIControl objects) do have properties like “selected”, “enabled”, “highlighted”. So there’s nothing special here.

  11. Akram says

    Nice Example… great one really

  12. Allen says

    Thanks Alexander.
    I wonder how did you show the progress in the UITextField you put on the navigationBar? I used a private API [UITextField setProgress:(float)value], but the result is very strange.

  13. Alexander Alexander says

    @Allen
    You don’t need a private API for this. All you need to do is to place a UIView with a semi-transparent background color on top of the URL field and resize this view based on the current progress value. And if you make sure that the user-interaction property for this UIView is switched off, all taps on this view will go directly to the URL field which is located below the progress view.

  14. Miri says

    Hi,
    Good explanation!
    If I want to refer this navBar instance, somewhere else in the code and change its leftBarButtonItem, how do I do it? I only succeed when I defined the navBar again and add it again to self.view. I assume there is a better way to do it.

    Thanks a lot,
    Miri

  15. Alexander Alexander says

    @Miri
    When using a UINavigationController, you can set the left and right buttons only under certain conditions, because the controller really controls almost everything at all times. This means you can usually only use the default behavior of the UINavigationController.
    When using a Navigation toolbar without a navigation controller you have much more freedom.

  16. Miri says

    Hi Alexander,

    That’s what I did – I used a Navigation toolbar without a navigation controller. I added a Navigation toolbar programmatically in viewDidLoad. Then, in another function, I wanted to change its leftBarButtonItem and I was able to do it only when I added again the Navigation toolbar.

    Thanks,
    Miri

  17. Alexander Alexander says

    @Miri
    I’m not sure what exactly you’re doing.Maybe you should create a small demo project and send it to me, so I can see what you’ve done.



Some HTML is OK

or, reply to this post via trackback.