【问题标题】:How do I implement a persistent/universal right bar button item like Music app and Pandora's "Now Playing" buttons?如何实现持久/通用右栏按钮项目,如音乐应用程序和 Pandora 的“正在播放”按钮?
【发布时间】:2013-02-26 17:50:06
【问题描述】:

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

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

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

Demo Project 带有我的层次结构的空白表示。

编辑:Pandora 的开发者 Neil Mix answered this question。完全一样的问题。但我不明白。如果有人能解释他的方法,那就太好了。

【问题讨论】:

  • 我认为您可以使用此答案,但不确定。类似问题:stackoverflow.com/a/12391120/1633251
  • @DavidH 没用。
  • 你是在 UIButton 上做的,对吧?好吧,如果这是我,我会创建一个带有按钮的最小演示项目,并添加一个小赏金,并且肯定会有人(或更多人)提供答案。玩一个项目比仅仅猜测它更容易。
  • @DavidH 当我的问题有资格获得赏金时,肯定会这样做。谢谢。
  • @DavidH 哇等等,我没有。我尝试将UIBarButtonItem 设置为静态变量并将其设置为右栏按钮。但这会导致行为不一致。该按钮仅在某些时候设置。

标签: ios uinavigationcontroller


【解决方案1】:

我为您实现了一个解决方案,它使用了一个单例 BarButtonManger,它被自定义 UINavigationController-subclass 用作委托。
您仍然需要决定按钮的目标应该是什么(VC 导航到,导航控制器,其他一些单例/应用程序委托,..)但是这个解决方案应该可以帮助您: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

【讨论】:

  • 我希望 NowPlayingController 从情节提要中实例化并在点击按钮时呈现。我该怎么做?
  • 您仍然可以在 CustomViewController 中实现-nowPlayingPressed 方法。更好:在 CustomNavigationController 中实现它并将 sharedItem.target = viewController 更改为 sharedItem.target = navigationController
  • 我找到了更好的方法。今晚会发布。
  • 我编辑了你的答案。如果我在 36 小时内没有得到更好的答案,我会接受。
【解决方案2】:

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

它使用与 Martin Ullrich 相同的策略,但还详细说明了如何在 Storyboard 中进行设置,这需要一些技巧。我将尝试在这里进行总结,因为我知道在 SO 中不鼓励仅发布链接。

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

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

【讨论】:

    【解决方案3】:

    没有太大的痛苦。您可能有一个“播放器”视图控制器。并在应用程序委托中创建一个变量日历“universalPlayer”。在您创建“播放器”对象时,您应该将其分配给“通用播放器”。然后将条形按钮添加到您的导航控制器。在 bar 按钮的操作上,您可以简单地从 AppDelegate 获取播放器视图控制器。这是一个简单的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      • 2020-03-27
      • 2021-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多