How can I change NSPopover
background color include triangle part?
Stefanf & Mike Bedar's solution for Swift 4:
import Cocoa
class PopoverContentView:NSView {
var backgroundView:PopoverBackgroundView?
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
if let frameView = self.window?.contentView?.superview {
if backgroundView == nil {
backgroundView = PopoverBackgroundView(frame: frameView.bounds)
backgroundView!.autoresizingMask = NSView.AutoresizingMask([.width, .height]);
frameView.addSubview(backgroundView!, positioned: NSWindow.OrderingMode.below, relativeTo: frameView)
}
}
}
}
class PopoverBackgroundView:NSView {
override func draw(_ dirtyRect: NSRect) {
NSColor.green.set()
self.bounds.fill()
}
}
In your storyboard, select the view which has your popover content and go to the Identity Inspector
Set the Class to PopoverContentView
Your popover and its triangle will now be green.
I faced the same problem, but I'm trying to avoid adding third party UI elements to my project, so I looked further. It seems if you override drawRect:
in the view of your popover's contentViewController
with setting a color like:
[[NSColor whiteColor] setFill];
NSRectFill([self bounds]);
then you'll end up having a popover with white background, except the triangle/arrow that connects it to the rect it is relative to. For solving that, you have to access the popover's border view which happened to contain the arrow:
NSView* borderView = [self.view.window valueForKeyPath:@"_borderView"];
I know, it is a private API, but if your goals not include submitting your app to the App Store, this is the easiest way to go. Now you can override the drawRect:
for this view as well. To avoid problems like having the private _borderView
property renamed with an SDK update, I suggest to assert for the borderView's existence before referencing it.
NSAssert(borderView, @"_borderView does not exist");