I have a strange bug with a custom rightBarButtomItem in the NavBar. I have a TabBar application. If the app is loaded the button shows up correct. If i click through the tabs the button keeps showing. If i go back to one of the tabs which was already shown the button disappears. At the end the button only shows randomly in one of the tabs.
My code works perfectly if i set a standard rightBarButtomItem programatically. But not with custom graphics. If a ChildViewController is pushed and popped the button appears again. It seems it is still there but not visible!
I think my referencing of the sharedRightButton within the CustomTabBarViewController is wrong!
Can anybody help?
CustomTabBarController.h
#import <UIKit/UIKit.h>
#import "EZBadgeView.h"
@interface CustomTabBarController : UITabBarController
{
EZBadgeView *badgeView;
UIButton *btn;
UIImage *rightBarButtonItemImage;
UIImage *rightBarButtonItemImageTapped;
UIImage *rightBarButtonItemImageSelected;
}
@property (nonatomic, strong) UIBarButtonItem *sharedRightButton;
@property (nonatomic, strong) EZBadgeView *badgeView;
@property(nonatomic, strong) UIButton *btn;
@property(nonatomic, strong) UIImage *rightBarButtonItemImage;
@property(nonatomic, strong) UIImage *rightBarButtonItemImageTapped;
@property(nonatomic, strong) UIImage *rightBarButtonItemImageSelected;
@end
CustomTabBarController.m
#import "CustomTabBarController.h"
@interface CustomTabBarController ()
@end
@implementation CustomTabBarController
@synthesize sharedRightButton, badgeView, btn, rightBarButtonItemImage, rightBarButtonItemImageSelected, rightBarButtonItemImageTapped;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBadgeNumber:) name:@"updateBadgeNumber" object:nil];
if (self.badgeView && self.badgeView.superview)
{
[self.badgeView removeFromSuperview];
}
self.badgeView = [[EZBadgeView alloc] init];
CGRect badgeFrame = self.badgeView.frame;
badgeFrame.origin.x = 31.0f;
badgeFrame.origin.y = -6.0f;
badgeFrame = CGRectIntegral(badgeFrame);
self.badgeView.frame = badgeFrame;
self.badgeView.badgeBackgroundColor = [self colorWithRGBHex:kRed withAlpha:1.0f];
self.badgeView.userInteractionEnabled = NO;
self.badgeView.badgeTextFont = [UIFont fontWithName:@"BrownStd-Bold" size:12];
self.badgeView.shouldShowGradient = NO;
self.badgeView.shouldShowShine = NO;
// Allocate UIButton
self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
self.btn.frame = CGRectMake(0, 0, 46, 30);
self.rightBarButtonItemImage = [UIImage imageNamed:@"button_mixer.png"];
[self.btn setBackgroundImage:rightBarButtonItemImage forState:UIControlStateNormal];
self.rightBarButtonItemImageTapped = [UIImage imageNamed:@"button_mixer_pressed.png"];
[self.btn setBackgroundImage:rightBarButtonItemImageTapped forState:UIControlStateHighlighted];
self.rightBarButtonItemImageSelected = [UIImage imageNamed:@"button_mixer_active.png"];
[self.btn setBackgroundImage:rightBarButtonItemImageSelected forState:UIControlStateSelected];
[self.btn addTarget:self action:@selector(clickedTest:) forControlEvents:UIControlEventTouchUpInside];
[self.btn setBackgroundColor:[UIColor clearColor]];
[self.btn addSubview:self.badgeView]; //Add NKNumberBadgeView as a subview on UIButton
// Initialize UIBarbuttonitem...
self.sharedRightButton = [[UIBarButtonItem alloc] initWithCustomView:btn];
self.badgeView.badgeValue = @"0";
self.badgeView.hidden = YES;
}
- (void)updateBadgeNumber:(NSMutableArray *)soundArray
{
self.badgeView.badgeValue = [NSString stringWithFormat:@"%i",[soundArray count]];
self.badgeView.hidden = ([soundArray count] == 0);
}
- (void)clickedTest:(id)sender
{
NSLog(@"%s", __FUNCTION__);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UIColor *)colorWithRGBHex:(UInt32)hex withAlpha:(float)alpha
{
int r = (hex >> 16) & 0xFF;
int g = (hex >> 8) & 0xFF;
int b = (hex) & 0xFF;
return [UIColor colorWithRed:r / 255.0f
green:g / 255.0f
blue:b / 255.0f
alpha:alpha];
}
@end
And i set the button like that in each view:
@implementation MyVC
@synthesize tabBarController;
- (void)viewDidLoad
{
//NSLog(@"begin: %s", __FUNCTION__);
[super viewDidLoad];
// right bar button from custom tabbarcontroller
self.tabBarController = [[CustomTabBarController alloc] init];
self.navigationItem.rightBarButtonItem = self.tabBarController.sharedRightButton;
}
It strikes me that creating a new
CustomTabBarController
for every view controller is fundamentally wrong, especially if it's to solve the problem that your right button isn't appearing. The issue is that you're creating new, phantom tab bar controllers, and worse, losing the reference to the view controller's real tab bar controller.Your solution gets to the kernel of the problem, which is that, because you're adding subviews for your button, namely creating the
UIBarButtonItem
withinitWithCustomView
, etc., that you cannot share the button with multiple navigation controllers. The shared, common right bar button works if you create a simpleUIBarButtonItem
withinitWithTitle
(or other simple variations like that), but it doesn't work if you do it with a custom view for your button.The right solution is to create a new
UIBarButtonItem
instance that has the behavior and appearance that you need. Then, any view controller that needs that bar button item can create an instance of that button. Thus, the new customRightBarButtonItem
might look like:RightBarButtonItem.h:
RightBarButtonItem.m:
Then, the
CustomTabBarController
is greatly simplified:CustomTabBarController.h:
CustomTabBarController.m:
And, finally, all of the view controllers that are added to the tab bar controller, can simply do:
All of this achieves the critical part of your proposed solution, namely to ensure that we have a unique instance of the right bar button item, but without the problem of creating redundant tab bar controllers.