Неспособность NSPopover, когда popover находится в строке состояния
Я делаю приложение, которое живет в строке состояния. При нажатии элемента состояния появляется сообщение NSPopover.
Он выглядит следующим образом:
![enter image description here]()
Здесь проблема: я хочу, чтобы она была "переходной", то есть, если я щелкнул где-нибудь за пределами popover, она закроется. И хотя NSPopoverBehaviorTransient отлично работает, когда popover находится в окне, он не работает, когда он находится в строке состояния.
Как я могу реализовать такое поведение самостоятельно?
Ответы
Ответ 1
Это оказалось легко:
- (IBAction)openPopover:(id)sender
{
// (open popover)
if(popoverTransiencyMonitor == nil)
{
popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask handler:^(NSEvent* event)
{
[self closePopover:sender];
}];
}
}
- (IBAction)closePopover:(id)sender
{
if(popoverTransiencyMonitor)
{
[NSEvent removeMonitor:popoverTransiencyMonitor];
popoverTransiencyMonitor = nil;
}
// (close popover)
}
Однако было нелегко, что есть неприятные проблемы с появлением popover из NSStatusItem (он не вел себя так, как хотелось бы, когда Mission Control был вызван или переключен в полноэкранное окно). Мне пришлось реализовать пользовательское окно, которое всегда плавает над NSStatusItem и имеет дело с переключением на полноэкранное окно и т.д. Это казалось легким, но явно элементы статуса не были предназначены для чего-то подобного:)
Ответ 2
Подход, который я использую, похож на приведенный выше ответ, за исключением того, что у меня все объединено в один метод вместо использования двух отдельных IBActions.
Сначала объявляю следующие свойства
@property (strong, nonatomic) NSStatusItem *statusItem;
@property (strong, nonatomic) NSEvent *popoverTransiencyMonitor;
@property (weak, nonatomic) IBOutlet NSPopover *popover;
@property (weak, nonatomic) IBOutlet NSView *popoverView;
то в awakeFromNib я установил элемент строки состояния
- (void)awakeFromNib {
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self.statusItem.title = @"Title";
self.statusItem.highlightMode = YES;
self.statusItem.action = @selector(itemClicked:);
}
за которым следует метод, вызываемый при нажатии элемента строки состояния
- (void)itemClicked:(id)sender {
[[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
if (self.popoverTransiencyMonitor == nil) {
self.popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyUpMask) handler:^(NSEvent* event) {
[NSEvent removeMonitor:self.popoverTransiencyMonitor];
self.popoverTransiencyMonitor = nil;
[self.popover close];
}];
}
}
который заставляет popover появляться и закрываться, когда пользователь щелкает за пределами представления.
Обратите внимание, что в Interface Builder вы должны установить поведение popover на Transient, чтобы popover закроется, когда пользователь нажмет на элемент состояния.