ステータスバーに住むアプリを作っています。ステータス項目をクリックすると、NSPopover がポップアップします。
次のようになります。

問題は次のとおりです。「一時的」にしたいのです。つまり、ポップオーバーの外側のどこかをクリックすると、ポップオーバーが閉じます。NSPopoverBehaviorTransient は、ポップオーバーがウィンドウにある場合は正常に機能しますが、ステータス バーにある場合は機能しません。
このような動作を自分で実装するにはどうすればよいですか?
ステータスバーに住むアプリを作っています。ステータス項目をクリックすると、NSPopover がポップアップします。
次のようになります。

問題は次のとおりです。「一時的」にしたいのです。つまり、ポップオーバーの外側のどこかをクリックすると、ポップオーバーが閉じます。NSPopoverBehaviorTransient は、ポップオーバーがウィンドウにある場合は正常に機能しますが、ステータス バーにある場合は機能しません。
このような動作を自分で実装するにはどうすればよいですか?
それは簡単であることが判明しました:
- (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)
}
ただし、簡単ではなかったのは、NSStatusItem からポップオーバーがポップアウトするという厄介な問題があることです (Mission Control が呼び出されたとき、またはスペースがフルスクリーン ウィンドウに切り替えられたときに、期待どおりに動作しませんでした)。常に NSStatusItem の上にフロートし、フルスクリーン ウィンドウへの切り替えなどを処理するカスタム ウィンドウを実装する必要がありました。
私が使用するアプローチは、2 つの個別の IBAction を使用する代わりに、すべてを 1 つのメソッドに結合することを除いて、上記の回答に似ています。
まず、次のプロパティを宣言します
@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];
}];
}
}
これにより、ポップオーバーが表示され、ユーザーがビューの外側をクリックすると閉じます。
Interface Builder では、ユーザーがステータス項目をクリックしたときにポップオーバーが閉じるように、ポップオーバーの動作を Transient に設定する必要があることに注意してください。