如何实现持久/通用右键栏项目,如音乐应用程序和潘多拉的“正在播放”按钮?

时间:2013-02-26 17:50:06

标签: ios uinavigationcontroller

我正在编写流媒体音乐应用程序,我非常喜欢音乐应用和Pandora中的通用“正在播放”按钮。我正在尝试自己实现它们。不幸的是,我尝试的方法让我和想要帮助我的人混淆了。这是我到目前为止所尝试的,所有这些都不起作用/部分工作:

  • 在所有控制器中使用static UIBarButtonItem(工作不一致,有时没有segue)
  • 手动向Interface Builder中的所有控制器添加按钮(有效,但在转换时会产生淡出/淡入动画)
  • 创建一个视图控制器,其中static UIBarButtonItem所有控制器都是子类化的(从方法1中消除了没有segue问题,但仍然表现不一致)

TL; DR:我不知道如何实现通用右键按钮项。请告诉我怎么做。

Demo Project,其中包含我的层次结构的空白表示。

编辑:潘多拉的开发者Neil Mix answered this question。完全相同的问题。但我不明白。如果有人可以解释他的方法,那将会很棒。

3 个答案:

答案 0 :(得分:3)

我为您实现了一个解决方案,它使用了一个单独的BarButtonManger,它由自定义UINavigationController - 子类用作委托。
您仍然需要确定按钮的目标应该是什么(VC导航到,navigaiton控制器,其他一些单例/应用代理,...),但此解决方案应该可以帮助您:http://cl.ly/3M151o1i3z3O
别忘了将故事板中导航控制器的类更改为CustomNavigationController!

//  BarButtonManager.h
#import <UIKit/UIKit.h>

@interface BarButtonManager : NSObject <UINavigationControllerDelegate>

+ (BarButtonManager*)sharedInstance;

@end


//  BarButtonManager.m
#import "BarButtonManager.h"

@implementation BarButtonManager {
    UIBarButtonItem *_sharedItem;
}

+ (BarButtonManager*)sharedInstance
{
    static BarButtonManager *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[BarButtonManager alloc] init];
    });
    return instance;
}


- (UIBarButtonItem*)sharedButtonItem
{
    if (!_sharedItem) { // not thread safe, but let's assume this is only called from UI thread
        UIButton *nowPlayingButton = [UIButton buttonWithType:UIButtonTypeCustom];

        UIImage *background = [[UIImage imageNamed:@"nav-bar-now-playing-button-silver.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(4.0, 7.5, 5.0, 13.0)];
        UIImage *backgroundPressed = [[UIImage imageNamed:@"nav-bar-now-playing-button-pressed-silver.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(4.0, 7.5, 5.0, 13.0)];

        [nowPlayingButton setBackgroundImage:background forState:UIControlStateNormal];
        [nowPlayingButton setBackgroundImage:backgroundPressed forState:UIControlStateHighlighted];

        nowPlayingButton.frame = CGRectMake(0.0, 0.0, background.size.width, background.size.height);

        NSMutableParagraphStyle *centre = [[NSMutableParagraphStyle alloc] init];
        centre.alignment = NSTextAlignmentCenter;
        centre.lineBreakMode = NSLineBreakByWordWrapping;


        NSMutableAttributedString *nowPlayingTitle = [[NSMutableAttributedString alloc] initWithString:@"Now Playing"];
        [nowPlayingTitle addAttributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:9.5], NSParagraphStyleAttributeName : centre, NSForegroundColorAttributeName : [UIColor whiteColor]} range:NSMakeRange(0, nowPlayingTitle.length)];


        [nowPlayingButton setAttributedTitle:nowPlayingTitle forState:UIControlStateNormal];

        nowPlayingButton.titleLabel.lineBreakMode = NSLineBreakByCharWrapping;
        nowPlayingButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
        nowPlayingButton.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
        [nowPlayingButton setTitleEdgeInsets:UIEdgeInsetsMake(0, -3, 0, 5)];

        [nowPlayingButton addTarget:nil action:@selector(nowPlayingPressed) forControlEvents:UIControlEventTouchUpInside];

        _sharedItem = [[UIBarButtonItem alloc] initWithCustomView:nowPlayingButton];
    }
    return _sharedItem;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    navigationController.topViewController.navigationItem.rightBarButtonItem = nil;
    UIBarButtonItem *sharedItem = [self sharedButtonItem];
    sharedItem.target = viewController;
    viewController.navigationItem.rightBarButtonItem = sharedItem;
}

@end


//  CustomNavigationController.h
#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

//  CustomNavigationController.m
#import "CustomNavigationController.h"
#import "BarButtonManager.h"

@implementation CustomNavigationController

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.delegate = [BarButtonManager sharedInstance];
    }
    return self;
}

@end

答案 1 :(得分:2)

我最近撰写了一篇关于此问题的博文:http://www.codebestowed.com/ios-shared-barbuttonitems

它采用与Martin Ullrich相同的策略,但也详细介绍了如何在故事板中进行设置,这需要一点点破解。我将在这里总结一下,因为我知道只是在SO中发布链接。

基本上,问题是当您将NavigationController拖动到Storyboard时,它不会为您创建可编辑的NavigationBar。要解决此问题,请创建一个ViewController并选择Editor-&gt; Embed In-&gt; Navigation Controller。通过此方法创建的NavigationController将具有可以将BarButtonItems拖动到的NavigationBar。将这个新控制器链接到您的UINavigationController的自定义子类,然后您可以为导航栏中的任何内容创建IBOutlets。

因此,结合使用此hack和Martin Ullrich的答案,将为您提供所需的功能+使用故事板功能的能力。

答案 2 :(得分:0)

没有太大的痛苦。你可能有一个'播放器'视图控制器。在app delegate中创建一个变量日历'universalPlayer'。在创建“播放器”对象时,您应该在“universalPlayer”上指定它。然后将栏按钮添加到导航控制器。在条形按钮的操作上,您只需从AppDelegate获取播放器视图控制器即可。这是一个简单的解决方案。