Как изменить цвет фона NSPopover, включите треугольную часть?

Как я могу изменить цвет фона NSPopover включить треугольник?

enter image description here

Ответы

Ответ 1

К сожалению, это действительно невозможно. NSPopover не был предназначен для настройки. Если вы хотите полностью настроить внешний вид, лучше всего использовать стороннюю замену NSPopover с открытым исходным кодом, например INPopoverController.

Ответ 2

На самом деле это намного проще, и вам не нужен частный 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

Swift 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)

}

Если вы хотите изменить только цвет фона popover (включая треугольник/стрелку), я решил, что вам не нужно создавать подкласс NSView. Нужный NSView с фоновым цветом должен быть достаточным.

Кроме того, вам не нужно вызывать super.viewDidMoveToWindow(), потому что его реализация по умолчанию ничего не делает.

Ответ 4

Благодаря Стефану я получил эту работу. Вот быстрая версия кода View. Как уже отмечалось, это должен быть класс для представления View как ваш контент-контент NSPopOver.

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)
    }
}

Ответ 5

У меня возникла та же проблема, но я стараюсь избегать добавления элементов интерфейса сторонних разработчиков в свой проект, поэтому я посмотрел дальше. Кажется, если вы переопределите drawRect: в представлении вашего popover contentViewController с настройкой цвета, например:

[[NSColor whiteColor] setFill];
NSRectFill([self bounds]);

тогда у вас будет popover с белым фоном, кроме треугольника/стрелки, которая соединяет его с прямоугольником, к которому он относится. Для решения этого вопроса вам нужно получить доступ к представлению пограничной границы, которое содержит стрелку:

NSView* borderView = [self.view.window valueForKeyPath:@"_borderView"];

Я знаю, что это частный API, но если ваши цели не включают отправку приложения в App Store, это самый простой способ. Теперь вы можете переопределить drawRect: для этого представления. Чтобы избежать таких проблем, как приватное свойство _borderView, переименованное с обновлением SDK, я предлагаю утверждать для существования borderView перед его ссылкой.

NSAssert(borderView, @"_borderView does not exist");

Ответ 6

Вот самое легкое решение этой проблемы, которое я нашел. Нет необходимости подклассифицировать NSView или добавлять любые подпрограммы.

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

Получить супервизор корневого представления popover, установить его цвет фона слоя.

Ответ 7

Решение Майка Бедара работает, но добавив еще одну вещь (чтобы получить треугольник, заполненный цветом фона), и это должно переопределить функцию draw внутри PopoverContentView как а также:

 override func draw(_ dirtyRect: NSRect) {
    backColor.set() // backColor is NSColor
    NSRectFill(self.bounds)
}