Система NSColor Цвет не меняется при переключении темного / светлого режима

Я пытаюсь изменить цвет изображения переключением темного / светлого режима в NSViewController. Я использую этот код для изменения цвета изображения:

- (NSImage *)image:(NSImage *)image withColour:(NSColor *)colour
{   
    NSImage *img = image.copy;
    [img lockFocus];
    [colour set];
    NSRect imageRect = NSMakeRect(0, 0, img.size.width, img.size.height);
    NSRectFillUsingOperation(imageRect, NSCompositingOperationSourceAtop);
    [img unlockFocus];
    return img;
}

Я пробовал вызвать этот метод из viewWillLayout

self.help1Image.image = [self image:self.help1Image.image withColour:[NSColor systemRedColor]];

но кажется, что системный цвет всегда возвращает одни и те же значения RGB.

Я также пробовал прислушиваться к уведомлению AppleInterfaceThemeChangedNotification, но даже здесь кажется, что значения RGB остаются прежними 1.000000 0.231373 0.188235.

[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification"
                                                             object:nil
                                                              queue:nil
                                                         usingBlock:^(NSNotification * _Nonnull note) {

                                                             NSLog(@"AppleInterfaceThemeChangedNotification");
                                                             self.help1Image.image = [self image:self.help1Image.image withColour:[NSColor systemRedColor]];

                                                             NSColorSpace *colorSpace = [NSColorSpace sRGBColorSpace];
                                                             NSColor *testColor = [[NSColor systemBlueColor] colorUsingColorSpace:colorSpace];
                                                             CGFloat red = [testColor redComponent];
                                                             CGFloat green = [testColor greenComponent];
                                                             CGFloat blue = [testColor blueComponent];
                                                             NSLog(@"%f %f %f", red, green, blue);
                                                         }];

У меня все нормально работает в NSButtonCell подклассе и layout переопределяется, но я не могу заставить его работать в NSViewController


person Darren    schedule 10.07.2019    source источник


Ответы (1)


Сначала проверьте раздел документации «Обновление пользовательских представлений с помощью определенных методов» здесь . Он говорит:

Когда пользователь изменяет внешний вид системы, система автоматически запрашивает перерисовку каждого окна и представления. Во время этого процесса система вызывает несколько хорошо известных методов как для macOS, так и для iOS, перечисленных в следующей таблице, для обновления вашего содержимого. Система обновляет среду признаков перед вызовом этих методов, поэтому, если вы внесете в них все изменения, зависящие от внешнего вида, ваше приложение обновится правильно.

Однако в этой таблице нет NSViewController методов.

Поскольку внешний вид представления может быть независимым от текущего или «системного» внешнего вида, лучший способ отреагировать на изменения внешнего вида в вашем контроллере представления - либо KVO свойство представления effectiveAppearance, либо сделать что-нибудь в [NSView viewDidChangeEffectiveAppearance].

- (void)viewDidLoad 
{
    [self addObserver:self forKeyPath:@"view.effectiveAppearance" options:0 context:nil];
}

// ...

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
    if ([keyPath isEqualToString:@"view.effectiveAppearance"])
    {
// ...

NSAppearance имеет свойство currentAppearance, которое не зависит от внешнего вида системы и обновляется Какао в перечисленных выше методах. В любом другом месте вам нужно будет убедиться, что это правильно. Идиоматический путь опять же через effectiveAppearance представления:

[NSAppearance setCurrentAppearance:someView.effectiveAppearance];

Итак, в вашем случае мне подходит следующее:

- (void)viewDidLoad 
{
    [super viewDidLoad];

    [self addObserver:self forKeyPath:@"view.effectiveAppearance" options:0 context:nil];
}

-(void)viewDidLayout
{
    self.help1Image.image = [self image:self.help1Image.image withColour:[NSColor systemRedColor]];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"view.effectiveAppearance"])
    {
                [NSAppearance setCurrentAppearance:self.view.effectiveAppearance];

                self.help1Image.image = [self image:self.help1Image.image withColour:[NSColor systemRedColor]];
    }
}
person TheNextman    schedule 12.07.2019
comment
Отличный ответ, спасибо. Ключевым моментом здесь было [NSAppearance setCurrentAppearance:self.view.effectiveAppearance];. Я могу указать это в уведомлении, которое я разместил в своем вопросе, и после этого цвета будут правильными. - person Darren; 15.07.2019