直接回答:
- 正如@tc.的回答所建议的那样,在 xib 中定义视图和使用视图控制器 (RightBarButtonItemVC) 在 UIBarButtonItem 上定义自定义视图之间存在脱节,这在 UIViewControllerWrapperView 接收到 buttonPressed 的事实中很明显调用而不是 RightBarButtonItemVC。看起来有些东西没有被保留,尽管我不确定是什么。
- 以下是我实施的具体工作解决方案。我确实做了一个类别,但不是为 UIViewControllerWrapperView 如前所述。
具体解决方案:
首先在 UIViewController 上创建一个 Objective-C 类别 BarButtonItemLoader:
@interface UIViewController (BarButtonItemLoader)
在 UIViewController+BarButtonItemLoader.h 中,定义这个方法:
- (UIBarButtonItem *) rightBarButtonItem;
由于您无法跟踪类别中的状态,因此在 AppDelegate.h 中定义一个 UIBarButtonItem:
@property (strong, nonatomic) UIBarButtonItem *rightBarButtonItem;
接下来,通过从 AppDelegate 延迟加载 rightBarButtonItem 开始实现类别的 rightBarButtonItem 方法(不要忘记#import "AppDelegate.h")。这确保了 AppDelegate 中只会创建和保留一个 rightBarButtonItem:
- (UIBarButtonItem *) rightBarButtonItem {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if(!appDelegate.rightBarButtonItem) {
//create a rightBarButtonItem (see below)
}
return appDelegate.rightBarButtonItem;
}
开始组装将设置为 rightBarButtonItem 的 UIView/UIBarButtonItem。从旧的 Interface Builder / xib 实现中传输每个元素/配置。最重要的是记下大小检查器中的框架信息,这样您就可以通过编程方式定位子视图,就像您在 .xib 文件中手动定位它们一样。
- (UIBarButtonItem *) rightBarButtonItem {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if(!appDelegate.rightBarButtonItem) {
UIView *rightBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 264, 44)];
UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightBarView];
UIImageView *textHeader = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"textHeader.png"]];
textHeader.frame = CGRectMake(2, 14, 114, 20);
[rightBarView addSubview:textHeader];
UIButton *button1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 2, 70, 44)];
[button1 setImage:[UIImage imageNamed:@"button1.png"] forState:UIControlStateNormal];
[button1 setImage:[UIImage imageNamed:@"button1Highlighted.png"] forState:UIControlStateHighlighted];
[button1 addTarget:self action:@selector(button1Pressed) forControlEvents:UIControlEventTouchUpInside];
[rightBarView addSubview:button1];
UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(194, 2, 70, 44)];
[button2 setImage:[UIImage imageNamed:@"button2.png"] forState:UIControlStateNormal];
[button2 setImage:[UIImage imageNamed:@"button2Highlighted.png"] forState:UIControlStateHighlighted];
[button2 addTarget:self action:@selector(button2Pressed) forControlEvents:UIControlEventTouchUpInside];
[rightBarView addSubview:button2];
appDelegate.rightBarButtonItem = rightBarButtonItem;
}
return appDelegate.rightBarButtonItem;
}
最后,根据您的目的实现 UIViewController+BarButtonItemLoader.m 中的 buttonXPressed 方法:
- (void) button1Pressed {
NSLog(@"button1 Pressed");
}
- (void) button2Pressed {
NSLog(@"button2 Pressed");
}
...
通过将此代码添加到任何 UIViewController 或其子类来使用该类别:
#import "UIViewController+BarButtonItemLoader.h"
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [self rightBarButtonItem];
}
概括
这种方法允许您将 UIBarButtonItem 即时添加到任何 UIViewController。缺点是您必须将上述代码添加到您创建的所有 UIViewControllers 中。
另外的选择
如果您想进一步封装 UIBarButtonItems(或其他任何内容)的添加,避免在每个 View Controller 中添加代码,您应该创建一个 BaseViewController,然后您可以从中继承所有其他 View Controller。从那里您可以考虑要包含在所有视图控制器中的其他项目。那么选择类别或子类路径就变成了一个粒度问题。