I finally got this to work!!
In short: You can't inherit or persist a UINavigationBar
, but you can set its UIBarButtonItem
s via its UINavigationItem
.
Here is what I did, followed by relevant code, followed by caveats:
What I Did:
1) Subclass UITabBarController: I created my own custom subclass of UITabBarController
. Since I want my two UIBarButtonItem
s to persist across tabs, I also created @property
s in my UITabBarController
subclass. Since I also want my UITabBarController
to handle these UIBarButtonItem
s, I also created one method for each button within my UITabBarController
subclass.
2) Embed View Controllers For Tabs In UINavigationControllers: This is the best way to get the desired effect even if you don't want or need a UINavigationController
because in iOS 7 the navigation bar extends upwards underneath the status bar to the top of the screen. (As far as I was able explore, I was unable to replicate this effect in iOS 7 using a UINavigationBar
without a UINavigationController
.)
3) Assign UIBarButtonItems To Top View Controllers: I assigned the UIBarButtonItem
s from my UITabBarController
subclass to my desired view controllers from within my tab bar controller's -[initWithNibName:bundle:]
and -[awakeFromNib]
methods. I did this by going through all of the view controllers assigned as tabs in my tab bar controller via self.viewControllers
; checking to see if they are UINavigationController
s; and assigning my UIBarButtonItem
s to my navigation controllers' top view controllers' navigation items via [navigationController.topViewController.navigationItem setLeftBarButtonItem:self.leftBarButton]
and [navigationController.topViewController.navigationItem setRightBarButtonItem:self.RightBarButton]
.
Relevant Code:
// MyTabBarController.h //
@interface MyTabBarController () <UITabBarControllerDelegate>
@property (nonatomic, strong) UIBarButtonItem *leftBarButton;
@property (nonatomic, strong) UIBarButtonItem *rightBarButton;
- (void)setup;
- (void)buttonLeft:(UIBarButtonItem *)sender;
- (void)buttonRight:(UIBarButtonItem *)sender;
@end
@implementation MyTabBarController
@synthesize leftBarButton = _leftBarButton;
@synthesize rightBarButton = _rightBarButton;
- (UIBarButtonItem *)leftBarButton
{
if (!_leftBarButton) _leftBarButton = [[UIBarButtonItem alloc] initWithTitle:@"Left" style:UIBarButtonItemStyleBordered target:self action:@selector(buttonLeft:)];
return _leftBarButton;
}
- (UIBarButtonItem *)rightBarButton
{
if (!_rightBarButton) _rightBarButton = [[UIBarButtonItem alloc] initWithTitle:@"Right" style:UIBarButtonItemStyleBordered target:self action:@selector(buttonRight:)];
return _rightBarButton;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
[self setup];
}
return self;
}
- (void)awakeFromNib
{
[self setup];
}
- (void)setup
{
[self setDelegate:self]; // since I am using myself as the UITabBarControllerDelegate
for (UIViewController *viewController in self.viewControllers)
{
if ([viewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)viewController;
[navigationController.topViewController.navigationItem setLeftBarButtonItem:self.leftBarButton];
[navigationController.topViewController.navigationItem setRightBarButtonItem:self.rightBarButton];
}
}
}
- (void)buttonLeft:(UIBarButtonItem *)sender
{
// Left bar button action
}
- (void)buttonRight:(UIBarButtonItem *)sender
{
// Right bar button action
}
@end
Caveats:
In the process of reaching my solution I learned a lot, including the following:
- You can't set your own UINavigationBar programmatically. At best, you can create your own custom
UINavigationBar
subclass and set it to your UINavigationController
via Interface Builder / Storyboard as described here (external website: iOS Dev Notes).
- You can't create and use a UINavigationBar from an XIB, as described here: How to customize UINavigationBar with XIB?
- Hacking together a combined "UITabBarController/UINavigationController" by dragging in a UINavigationBar and UITabBar into a UIViewController doesn't work in iOS 7, since iOS 7 uses overlapping translucent UI elements whose overlaps can't be set well programmatically (e.g., the extension of the navigation bar behind the status bar).
- Embedding a UITabBarController in a UINavigationController works but is explicitly discouraged / forbidden by Apple's documentation. This is because it's bad logic to embed a top-level navigation feature (i.e., a UITabBarController that allows the user to switch between parallel interfaces) in a UI that's supposed to be able to push and pop its view controllers.