23

如何更改NSPopover背景颜色包括三角形部分?

在此处输入图像描述

4

8 回答 8

54

它实际上要简单得多,并且您不需要私有 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
于 2015-06-05T07:37:36.473 回答
13

斯威夫特 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(),因为它的默认实现什么都不做。

于 2016-09-19T12:09:19.070 回答
9

感谢 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)
    }
}
于 2016-04-22T21:34:02.867 回答
7

我遇到了同样的问题,但我试图避免将第三方 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");
于 2015-04-25T07:28:32.547 回答
6

这是我发现的这个问题的最简单的解决方案。无需继承 NSView 或添加任何子视图。

NSView *popoverView = [[[[self popover] contentViewController] view] superview];
[popoverView setWantsLayer:YES];
[[popoverView layer] setBackgroundColor:[[NSColor colorWithWhite:0.8 alpha:1] CGColor]];

获取popover根视图的superview,设置其layer的背景颜色。

于 2016-10-21T23:32:14.900 回答
3

Stefanf & Mike Bedar 的 Swift 4 解决方案:

  1. 转到文件->新建文件->可可类
  2. 给你的班级命名。例如。弹出内容视图。确保它是 NSView 的子类
  3. 将文件内容设置为:
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()
    }
}
  1. 在您的故事板中,选择包含您的弹出内容的视图并转到身份检查器

  2. 将类设置为 PopoverContentView

您的弹出框及其三角形现在将变为绿色。

于 2018-07-01T08:53:28.447 回答
0

不幸的是,这实际上是不可能的。NSPopover 的设计初衷不是可定制的。如果你想要一个完全定制的外观,你最好的选择可能是使用第三方的开源 NSPopover 替代品,比如INPopoverController

于 2013-11-14T18:48:30.280 回答
0

Mike Bedar 的解决方案是有效的,但只添加了一件东西(为了让三角形填充背景颜色),那就是覆盖PopoverContentView内的绘制函数:

 override func draw(_ dirtyRect: NSRect) {
    backColor.set() // backColor is NSColor
    NSRectFill(self.bounds)
}
于 2018-01-26T16:00:00.983 回答