如何更改NSPopover
背景颜色包括三角形部分?
8 回答
它实际上要简单得多,并且您不需要私有 API。
使视图控制器的根视图成为自定义类
@implementation MyPopoverRootView
-(void)viewDidMoveToWindow
{
NSView * aFrameView = [[self.window contentView] superview];
MyPopoverBackgroundView * aBGView =[[MyPopoverBackgroundView alloc] initWithFrame:aFrameView.bounds];
aBGView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[aFrameView addSubview:aBGView positioned:NSWindowBelow relativeTo:aFrameView];
[super viewDidMoveToWindow];
}
@end
您的背景视图只是在其边界内绘制所需的颜色。
@implementation MyPopoverBackgroundView
-(void)drawRect:(NSRect)dirtyRect
{
[[NSColor whiteColor] set];
NSRectFill(self.bounds);
}
@end
斯威夫特 3
override func viewDidMoveToWindow() {
guard let frameView = window?.contentView?.superview else {
return
}
let backgroundView = NSView(frame: frameView.bounds)
backgroundView.wantsLayer = true
backgroundView.layer?.backgroundColor = .white // colour of your choice
backgroundView.autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
frameView.addSubview(backgroundView, positioned: .below, relativeTo: frameView)
}
如果您只想更改弹出框的背景颜色(包括三角形/箭头),我认为您不需要创建 NSView 的子类。具有背景颜色的层支持的 NSView 就足够了。
此外,您不需要调用super.viewDidMoveToWindow()
,因为它的默认实现什么都不做。
感谢 Stefanf,我得到了这个工作。这是视图代码的 Swift 版本。如前所述,这应该是作为 NSPopOver contentView 的视图集的类。
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 = NSAutoresizingMaskOptions([.ViewWidthSizable, .ViewHeightSizable]);
frameView.addSubview(backgroundView!, positioned: NSWindowOrderingMode.Below, relativeTo: frameView)
}
}
}
}
class PopoverBackgroundView:NSView {
override func drawRect(dirtyRect: NSRect) {
NSColor.redColor().set()
NSRectFill(self.bounds)
}
}
我遇到了同样的问题,但我试图避免将第三方 UI 元素添加到我的项目中,所以我进一步研究。似乎如果您drawRect:
在弹出窗口的视图中覆盖contentViewController
设置颜色,例如:
[[NSColor whiteColor] setFill];
NSRectFill([self bounds]);
那么你最终会得到一个带有白色背景的弹出框,除了将它连接到它相对的矩形的三角形/箭头。为了解决这个问题,您必须访问恰好包含箭头的弹出框的边框视图:
NSView* borderView = [self.view.window valueForKeyPath:@"_borderView"];
我知道,这是一个私有 API,但如果您的目标不包括将您的应用程序提交到 App Store,这是最简单的方法。现在你也可以覆盖drawRect:
这个视图。为了避免_borderView
使用 SDK 更新重命名私有属性等问题,我建议在引用它之前断言borderView 的存在。
NSAssert(borderView, @"_borderView does not exist");
这是我发现的这个问题的最简单的解决方案。无需继承 NSView 或添加任何子视图。
NSView *popoverView = [[[[self popover] contentViewController] view] superview];
[popoverView setWantsLayer:YES];
[[popoverView layer] setBackgroundColor:[[NSColor colorWithWhite:0.8 alpha:1] CGColor]];
获取popover根视图的superview,设置其layer的背景颜色。
Stefanf & Mike Bedar 的 Swift 4 解决方案:
- 转到文件->新建文件->可可类
- 给你的班级命名。例如。弹出内容视图。确保它是 NSView 的子类
- 将文件内容设置为:
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()
}
}
在您的故事板中,选择包含您的弹出内容的视图并转到身份检查器
将类设置为 PopoverContentView
您的弹出框及其三角形现在将变为绿色。
不幸的是,这实际上是不可能的。NSPopover 的设计初衷不是可定制的。如果你想要一个完全定制的外观,你最好的选择可能是使用第三方的开源 NSPopover 替代品,比如INPopoverController。
Mike Bedar 的解决方案是有效的,但只添加了一件东西(为了让三角形填充背景颜色),那就是覆盖PopoverContentView内的绘制函数:
override func draw(_ dirtyRect: NSRect) {
backColor.set() // backColor is NSColor
NSRectFill(self.bounds)
}