Подтвердить что ты не робот

NSStatusItem изменить изображение для темного оттенка

С OSX 10.10 beta 3 Apple выпустила свой темный оттенок. К сожалению, это также означает, что практически все значки состояния (за исключением Apple и Path Finder, которые я видел), включая мои, остаются темными на темном фоне. Как я могу предоставить альтернативное изображение, если применяется темный оттенок?

Я не вижу изменения API на NSStatusBar или NSStatusItem, который показывает мне изменения, я предполагаю, что это уведомление или что-то реактивное, чтобы легко внести изменения, поскольку пользователь изменяет оттенок.

Текущий код для рисования изображения заключен в NSView:

- (void)drawRect:(NSRect)dirtyRect
{
    // set view background color
    if (self.isActive) {
        [[NSColor selectedMenuItemColor] setFill];
    } else {
        [[NSColor clearColor] setFill];
    }

    NSRectFill(dirtyRect);

    // set image
    NSImage *image = (self.isActive ? self.alternateImage : self.image);
    _imageView.image = image;
}
4b9b3361

Ответ 1

TL; DR: Вам не нужно ничего делать в Dark Theme. Дайте NSStatusItem (или NSStatusBarButton) образ шаблона, и он будет корректно стилизовать его в любом контекстном меню.


Причина, по которой некоторые элементы статуса приложений (такие как PathFinder) уже работают в Dark Theme, заключается в том, что они не настраивают собственное пользовательское представление в StatusItem, а устанавливают только шаблон изображения в StatusItem.

Что-то вроде:

_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
NSImage *image = [NSImage imageNamed:@"statusItemIcon"];
[image setTemplate:YES];
[_statusItem setImage:image];

Это работает точно так же, как вы ожидали в Mavericks и ранее, а также в Yosemite и в любых будущих выпусках, поскольку он позволяет AppKit выполнять весь стиль изображения в зависимости от состояния статусных элементов.

Mavericks

В Mavericks (и ранее) было всего 2 уникальных стиля предметов. Не нажато и нажато. Эти два стиля в значительной степени выглядели чисто черными и чисто белыми соответственно. (На самом деле "чисто черный" не совсем корректен - был небольшой эффект, который заставил их выглядеть немного вставками).

Поскольку существовало только два возможных состояния, приложения состояния-бара могли устанавливать свой собственный вид и легко получать одинаковый внешний вид, просто рисуя черный или белый в зависимости от их выделенного состояния. (Но еще раз обратите внимание, что это не было чисто черным, поэтому приложения либо должны были создавать эффект в изображении, либо быть довольны едва заметной изящной иконкой).

Yosemite

В Йосемите существует не менее 32 уникальных стилей предметов. Unpressed in Dark Theme является лишь одним из них. Нет никакого практического (или непрактичного) способа для приложения, чтобы иметь возможность делать свой собственный стиль элементов и выглядеть корректно во всех контекстах.

Вот примеры из шести возможных стилей:

Six possible status item stylings

Элементы состояния на неактивной панели меню теперь имеют определенный стиль, в отличие от простого изменения непрозрачности, как в прошлом. Внешний вид - это еще одно возможное изменение; есть и другие дополнительные размеры этой матрицы возможностей.

API

Произвольные представления, установленные как свойство NSStatusItem view, не имеют возможности фиксировать все эти варианты, поэтому он (и другой связанный API) устарел в 10.10.

Однако семя 3 вводит новый API в NSStatusItem:

@property (readonly, strong) NSStatusBarButton *button NS_AVAILABLE_MAC(10_10);

Эта часть API имеет несколько целей:

  • Теперь приложение может отображать позицию экрана (или отображать popover) из элемента состояния без установки собственного пользовательского представления.
  • Удаляет потребность в API, например image, title, sendActionOn: на NSStatusItem.
  • Предоставляет класс для нового API: т.е. looksDisabled. Это позволяет приложениям получать стандартную функцию отключения/выключения (например, Bluetooth/Time Machine при выключении), не требуя специального изображения.

Если что-то, что невозможно сделать с текущим (нестандартным представлением) API, пожалуйста, напишите для него запрос расширения. StatusItems должен обеспечивать поведение или внешний вид таким образом, чтобы он был стандартным для всех элементов состояния.


Больше обсуждений на https://devforums.apple.com/thread/234839, хотя я кратко изложил здесь все.

Ответ 2

В итоге я сделал что-то вроде следующего для моего пользовательского перетаскивания NSStatusItemView: (с помощью Swift)

var isDark = false

func isDarkMode() {
    isDark = NSAppearance.currentAppearance().name.hasPrefix("NSAppearanceNameVibrantDark")
}

override func drawRect(dirtyRect: NSRect) {
    super.drawRect(dirtyRect)
    isDarkMode()
    // Now use "isDark" to determine the drawing colour.
    if isDark {
        // ...
    } else {
        // ...
    }
}

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

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

Ответ 3

Я создал базовую оболочку вокруг NSStatusItem, которую вы можете использовать для поддержки 10.10 и более ранних с пользовательскими представлениями в строке состояния. Вы можете найти его здесь: https://github.com/noahsmartin/YosemiteMenuBar Основная идея состоит в том, чтобы нарисовать пользовательский вид в NSImage и использовать это изображение в качестве изображения шаблона для элемент состояния. Эта оболочка также пересылает события события в пользовательский вид, поэтому их можно обрабатывать так же, как и до 10.10. Проект содержит базовый пример того, как YosemiteMenuBar можно использовать с пользовательским представлением в строке состояния.

Ответ 4

Когда ваше приложение нарисовало какой-либо элемент GUI, вы можете получить его внешний вид через [NSAppearance currentAppearance], который сам имеет свойство name, которое содержит что-то вроде

NSAppearanceNameVibrantDark->NSAppearanceNameAqua->NSAppearanceNameAquaMavericks

Первая часть - это имя появления, которое также доступно как константа в NSAppearanceNameVibrantDark или NSAppearanceNameVibrantLight.

Я не знаю, есть ли способ получить только первую часть, но я думаю, что сейчас это трюк.

Пример кода:

-(void)awakeFromNib {
    NSStatusItem* myStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
    myStatusItem.title = @"Hello World";

    if ([[[NSAppearance currentAppearance] name] containsString:NSAppearanceNameVibrantDark]) {
        myStatusItem.title = @"Dark Interface";
    } else {
        myStatusItem.title = @"Light Interface";
    }
}

Ответ 5

Но на всякий случай, если вы хотите отслеживать изменения статуса, вы можете. Я также знаю, что есть лучший способ определить режим Lite/Dark, чем то, что было сказано выше, но я помню его прямо сейчас.

// Monitor menu/dock theme changes...
[[NSDistributedNotificationCenter defaultCenter] addObserver: self selector: @selector(themeChange:) name:@"AppleInterfaceThemeChangedNotification" object: NULL];

//
-(void) themeChange :(NSNotification *) notification
{
    NSLog (@"%@", notification);
}