Как вручную создать динамические (темные / светлые) экземпляры NSImage?

Кажется, в MacOS 10.14 Mojave, единственный способ создать NSImage экземпляры, которые автоматически рисуют светлую и темную версию через каталоги активов и +[NSImage imageNamed:], Однако мне нужно создавать динамические образы во время выполнения, и, похоже, нет способа сделать это без использования частного API.

Под капотом, похоже, частная собственность _appearanceName был введен в NSImageRep это каким-то образом используется для выбора правильного представления. Это должно быть прямо вперед, чтобы создать NSImage с изображениями, которые имеют соответствующие _appearanceName установить, но я хотел бы избежать этого.

Я нашел простой обходной путь (опубликован ниже), но он, кажется, не работает правильно, когда внешний вид системы меняется (т. Е. Пользователь переключается со светлого на темный или наоборот) или когда используется в иерархиях представления, которые имеют appearance свойство устанавливается на различные виды (например, один вид жестко закодирован в режиме темного, другой вид жестко закодирован в режиме светлого).

Итак, как я могу вручную создать динамический NSImage это правильно показывает светлую или темную версию, как это делают изображения из каталога активов?


@implementation NSImage (CustomDynamic)

+ (NSImage *)imageWithLight:(NSImage *)light dark:(NSImage *)dark
{
    if (@available(macOS 10.14, *)) {
        return [NSImage
            imageWithSize:light.size
            flipped:NO
            drawingHandler:^(NSRect dstRect) {
                if ([NSImage appearanceIsDarkMode:NSAppearance.currentAppearance]) {
                    [dark drawInRect:dstRect];
                } else {
                    [light drawInRect:dstRect];
                }
                return YES;
            }
        ];
    } else {
        return light;
    }
}

+ (BOOL)appearanceIsDarkMode:(NSAppearance *)appearance
{
    if (@available(macOS 10.14, *)) {
        NSAppearanceName basicAppearance = [appearance bestMatchFromAppearancesWithNames:@[
            NSAppearanceNameAqua,
            NSAppearanceNameDarkAqua
        ]];
        return [basicAppearance isEqualToString:NSAppearanceNameDarkAqua];

    } else {
        return NO;
    }
}

@end

1 ответ

Решение

Выяснилось, что код, указанный в вопросе, работает просто отлично! Обработчик рисования фактически вызывается в подходящее время и обрабатывает все ситуации внешнего вида.

Тем не менее, у меня был код, который масштабировал и кэшировал эти изображения, и он все еще использовал древние [image lockFocus]; … [image unlockFocus]; способ рисования изображений вместо использования +[NSImage imageWithSize:flipped:drawingHandler:],

Другие вопросы по тегам