Adding a toolbar to UIImagePickerController

For an iPad app I was working on recently, I wanted to be able to show a toolbar on the bottom of a UIPopoverController which was being used to present a UIImagePickerController. It turned out this was a non-trivial problem to solve.

On iPad you are meant to display the image picker inside a popover. My first attempt was to ignore this and create a new view controller that had a main view and a toolbar. I added the image picker into to the main view and presented the whole thing in a popover:

UIImagePickerController *imagePicker = [UIImagePickerController alloc] init];
ToolbarPickerController *toolbarPicker = [ToolbarPickerController alloc] init];
[toolbarPicker.mainView addSubview:imagePicker.view];

UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:toolbarPicker];

This worked but was unsatisfactory for a few reasons:

  • The popover controller normally makes UINavigationController content look like its part of the popover itself (it styles the navigation bar, and any toolbars, to blend perfectly into the popover border). Because my new view controller was not a UINavigationController, but hosted one instead (UIImagePickerController), the popover did not apply the correct appearance.
  • The image picker thought it was modal and displayed a cancel button. It doesn’t do this normally when displayed in a popover. It was impossible to get rid of the cancel button and it was jarring. I also got a few warnings about a missing style while debugging.

In fact, this had not been my first attempt. Initially I had planned to simply add some toolbar items to the UIImagePickerController but gave up very quickly when this didn’t work. I decided to try again…but a bit harder.

My initial attempt had been to do something like this prior to displaying the popover:

imagePicker.toolbarHidden = NO;
imagePicker.toolbarItems = [NSArray arrayWithObjects…];

This doesn’t work, and its flawed. Firstly, the image picker forcibly hides the toolbar as soon as it presents anything. Secondly, the image picker is a navigation controller and therefore it sets its toolbar items from whatever view controller it is presenting. I wanted a consistent toolbar that would be visible all the time.

It turns out the solution is to show the toolbar and set the toolbar items on the top view controller every time the image picker presents a view controller. This can be achieved by implementing a couple of UINavigationControllerDelegate methods:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
  if (navigationController == self.imagePicker)
  {
    [self.imagePicker setToolbarHidden:NO animated:NO];
    [self.imagePicker.topViewController setToolbarItems:self.toolbarItems animated:NO];
  }
}

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
  if (navigationController == self.imagePicker)
  {
    [self.imagePicker setToolbarHidden:NO animated:NO];
    [self.imagePicker.topViewController setToolbarItems:self.toolbarItems animated:NO];
  }
}

You have to put the code in both methods. If you don’t, some transitions will hide the toolbar and it might not appear when initially displayed.