【问题标题】:Custom rightBarButtonItem disappearing自定义 rightBarButtonItem 消失
【发布时间】:2013-02-20 01:48:33
【问题描述】:

我在导航栏中的自定义 rightBarButtomItem 有一个奇怪的错误。我有一个 TabBar 应用程序。如果应用程序已加载,则按钮显示正确。如果我单击选项卡,则按钮会一直显示。如果我回到已经显示的选项卡之一,按钮就会消失。最后,该按钮仅随机显示在其中一个选项卡中。

如果我以编程方式设置标准 rightBarButtomItem,我的代码将完美运行。但不适用于自定义图形。如果 ChildViewController 被按下并弹出,按钮会再次出现。它似乎还在,但不可见!

我认为我在 CustomTabBarViewController 中对 sharedRightButton 的引用是错误的!

有人可以帮忙吗?

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

我在每个视图中都设置了这样的按钮:

@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;

}

【问题讨论】:

  • 尝试在 ViewWillAppear 或 ViewDidAppear 中设置按钮
  • 这是我尝试的第一个。那也没用。 TabBarController 似乎有问题。但我不知道。

标签: ios uitabbarcontroller custom-controls uinavigationbar rightbarbuttonitem


【解决方案1】:

让我感到震惊的是,为每个视图控制器创建一个新的CustomTabBarController 从根本上来说是错误的,特别是如果它是为了解决您的右键没有出现的问题。问题是您正在创建新的虚拟标签栏控制器,更糟糕的是,丢失了对视图控制器的真实标签栏控制器的引用。

您的解决方案触及问题的核心,因为您正在为按钮添加子视图,即使用initWithCustomView 创建UIBarButtonItem 等,因此您无法与多个导航共享按钮控制器。如果您使用initWithTitle(或其他类似的简单变体)创建一个简单的UIBarButtonItem,则共享的公共右栏按钮有效,但如果您为按钮使用自定义视图,则它不起作用。

正确的解决方案是创建一个具有您需要的行为和外观的新 UIBarButtonItem 实例。然后,任何需要该条形按钮项的视图控制器都可以创建该按钮的实例。因此,新的自定义 RightBarButtonItem 可能如下所示:

RightBarButtonItem.h:

@interface RightBarButtonItem : UIBarButtonItem

- (id)initWithTarget:(id)target action:(SEL)action;

@end

RightBarButtonItem.m:

@interface RightBarButtonItem ()
@property (nonatomic, strong) EZBadgeView *badgeView;
@end

@implementation RightBarButtonItem

- (id)initWithTarget:(id)target action:(SEL)action
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(0, 0, 46, 30);

    self = [super initWithCustomView:button];

    if (self)
    {
        _badgeView = [[EZBadgeView alloc] init];
        CGRect badgeFrame = self.badgeView.frame;
        badgeFrame.origin.x = 31.0f;
        badgeFrame.origin.y = -6.0f;
        badgeFrame = CGRectIntegral(badgeFrame);
        _badgeView.frame = badgeFrame;
        _badgeView.badgeBackgroundColor = [self colorWithRGBHex:kRed withAlpha:1.0f];
        _badgeView.userInteractionEnabled = NO;
        _badgeView.badgeTextFont = [UIFont fontWithName:@"BrownStd-Bold" size:12];
        _badgeView.shouldShowGradient = NO;
        _badgeView.shouldShowShine = NO;

        [button setBackgroundImage:[UIImage imageNamed:@"button_mixer.png"]         forState:UIControlStateNormal];
        [button setBackgroundImage:[UIImage imageNamed:@"button_mixer_pressed.png"] forState:UIControlStateHighlighted];
        [button setBackgroundImage:[UIImage imageNamed:@"button_mixer_active.png"]  forState:UIControlStateSelected];

        [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
        [button setBackgroundColor:[UIColor clearColor]];
        [button addSubview:_badgeView]; //Add NKNumberBadgeView as a subview on UIButton

        _badgeView.badgeValue = @"0";
        _badgeView.hidden = YES;

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(updateBadgeNumber:)
                                                     name:@"updateBadgeNumber"
                                                   object:nil];
    }

    return self;
}

- (void)dealloc
{
    // don't forget to have mechanism to remove the observer when this button is deallocated

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:@"updateBadgeNumber"
                                                  object:nil];
}

- (void)updateBadgeNumber:(NSMutableArray *)soundArray
{
    self.badgeView.badgeValue = [NSString stringWithFormat:@"%i",[soundArray count]];
    self.badgeView.hidden = ([soundArray count] == 0);
}

- (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

那么CustomTabBarController就大大简化了:

CustomTabBarController.h:

@interface CustomTabBarController : UITabBarController

- (UIBarButtonItem *)rightBarButton;

@end

CustomTabBarController.m:

#import "RightBarButtonItem.h"

@implementation CustomTabBarController

- (UIBarButtonItem *)rightBarButton
{
    return [[RightBarButtonItem alloc] initWithTarget:self
                                               action:@selector(clickedTest:)];
}

- (void)clickedTest:(id)sender
{
    NSLog(@"%s", __FUNCTION__);
}

@end

最后,添加到标签栏控制器的所有视图控制器都可以简单地做:

- (void)viewDidLoad
{
    [super viewDidLoad];

    CustomTabBarController *tabBarController = (id)self.tabBarController;

    self.navigationItem.rightBarButtonItem = [tabBarController rightBarButton];
}

所有这些都实现了您提出的解决方案的关键部分,即确保我们有一个唯一的右栏按钮项目实例,但不存在创建冗余标签栏控制器的问题。

【讨论】:

  • 我现在更改了我的代码,它运行良好!再一次非常感谢你!!!我看到您的代码比我的代码干净得多:您将接口和属性定义放在实现文件中。我以前见过,但不确定它有什么不同。另一件事是使用带有 uderscore 的属性,例如 _badgeView 与 badgeView。我以前也看到过,但不明白。你能给我一个解释它的链接吗?
  • @rockstarberlin - 将一些属性定义放在 .m 文件中(在所谓的“私有类扩展”中)的想法是将 .h 文件限制为其他需要的公共接口类并将私有实现的所有血腥细节保存在 .m 文件中。它在功能上是相同的(就 .m 文件而言),但是当您在将来的某个日期使用该类时,它会更干净且不会造成混淆。我还注意到您有一些仅在初始化期间才需要的属性,所以我只是制作了那些局部变量(或完全摆脱了变量)。
  • @rockstarberlin 关于 _ 变量,微妙的问题是您不应该在初始化方法中使用访问器方法(self. 前缀)。见Practical Memory Management
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 2023-04-03
  • 2014-02-22
相关资源
最近更新 更多