不幸的是,没有干净的方法可以做到这一点。不过幸运的是,我在 Delicious Library 3 中采用了一种丑陋的方式——您需要将此方法放在 NSWindow 的子类中,并确保所讨论的文档窗口是该子类:
- (BOOL)makeFirstResponder:(NSResponder *)responder;
{
// Prevent popover content view from forcing our current first responder to resign
if (responder != self.firstResponder && [responder isKindOfClass:[NSView class]]) {
NSWindow *const newFirstResponderWindow = ((NSView *)responder).window;
NSWindow *currentFirstResponderWindow;
NSResponder *const currentFirstResponder = self.firstResponder;
if ([currentFirstResponder isKindOfClass:[NSWindow class]])
currentFirstResponderWindow = (id)currentFirstResponder;
else if ([currentFirstResponder isKindOfClass:[NSView class]])
currentFirstResponderWindow = ((NSView *)currentFirstResponder).window;
// Prevent some view in popover from stealing our first responder, but allow the user to explicitly activate it with a click on the popover.
// Note that the current first responder may be in a child window, if it's a control in the "thick titlebar" area and we're currently full-screen.
if (newFirstResponderWindow != self && newFirstResponderWindow != currentFirstResponderWindow && self.currentEvent.window != newFirstResponderWindow)
for (NSView *responderView = (id)responder; responderView; responderView = responderView.superview)
if ([responderView conformsToProtocol:@protocol(LIPopoverFirstResponderStealingSuppression)] &&
((id <LIPopoverFirstResponderStealingSuppression>)responderView).suppressFirstResponderWhenPopoverShows)
return NO;
}
return [super makeFirstResponder:responder];
}
现在确保弹出框的内容视图子类实现了这个协议:
// NSPopover doesn't respect -acceptsFirstResponder of its content view (Radar 10666891).
@protocol LIPopoverFirstResponderStealingSuppression <NSObject>
@property (readonly, nonatomic) BOOL suppressFirstResponderWhenPopoverShows;
@end
还请向 Apple 提交错误以请求 NSPopover 尊重 -acceptsFirstResponder 的内容视图;100% 的情况是,当多个开发人员提交错误时,他们会得到修复。