Как проверить, включен ли темный режим в iOS/iPadOS?

Начиная с iOS/iPadOS 13 доступен темный стиль пользовательского интерфейса, аналогичный темному режиму, представленному в macOS Mojave. Как я могу проверить, включил ли пользователь общесистемный темный режим?

Этот пользовательский интерфейс фактически был доступен с tvOS 10 и iOS 12 — в iOS 12 он был просто доступен как «инвертировать цвета» в параметрах специальных возможностей.

Aaron Brager 05.06.2019 04:46

Комментарий Аарона Брагера несколько неточен — да, вы можете «инвертировать цвета», но это сильно отличается от включения темного режима. Это может создать ложное впечатление, что ваше приложение все еще можно использовать. например: если вы непреднамеренно смешали системные цвета со своими собственными, функция инвертирования инвертирует их все. Однако в темном режиме системные цвета изменятся, а ваши — нет. Таким образом, как и в случае с Touchgram v1.1.0, вы можете получить почти белый текст на очень бледно-голубом фоне. В обзоре App Store это НЕ указано!

Andy Dent 28.03.2020 05:24

Вот Чтобы проверить текущее состояние, а это для Наблюдение за живыми изменениями состояния. Оба ответа охватывают UIKit/AppKit/SwiftUI и т. д.

Mojtaba Hosseini 04.09.2020 03:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
66
3
29 185
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Вы должны проверить переменную userInterfaceStyle для UITraitCollection, как и в tvOS и macOS.

switch traitCollection.userInterfaceStyle {
case .light: //light mode
case .dark: //dark mode
case .unspecified: //the user interface style is not specified
}

Вы должны использовать функцию traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)UIView/UIViewController для обнаружения изменений в среде интерфейса (включая изменения в стиле пользовательского интерфейса).

Из Документация для разработчиков Apple:

The system calls this method when the iOS interface environment changes. Implement this method in view controllers and views, according to your app’s needs, to respond to such changes. For example, you might adjust the layout of the subviews of a view controller when an iPhone is rotated from portrait to landscape orientation. The default implementation of this method is empty.

Элементы пользовательского интерфейса по умолчанию (например, UITabBar или UISearchBar) автоматически адаптируются к новому стилю пользовательского интерфейса.

В дополнение к traitCollectionDidChange(_:) вы также можете проверить изменение в UIView, layoutSubviews(), draw(_:) или updateConstraints() или в tintColorDidChange(), UIViewController или updateViewConstraints(). Все эти методы вызываются каждый раз при изменении стиля пользовательского интерфейса.

Aaron Brager 05.06.2019 04:48

Это даст вам стиль пользовательского интерфейса текущего представления. Если вы переопределили его для этого конкретного представления, он не скажет вам стиль системы.

davextreme 06.09.2019 00:03

Как упоминал daveextreme, проверка стиля пользовательского интерфейса текущего представления не всегда возвращает системный стиль при использовании свойства overrideUserInterfaceStyle. В таких случаях может быть лучше использовать следующий код:

switch UIScreen.main.traitCollection.userInterfaceStyle {
case .light: //light mode
case .dark: //dark mode
case .unspecified: //the user interface style is not specified
}

Этот ответ лучше всего подходит для проверки темы в классе, отличном от UIViewController.

Kozmotronik 24.09.2021 11:13

Лучшей точкой для обнаружения изменений является функция traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) UIView/UIViewController.

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    let userInterfaceStyle = traitCollection.userInterfaceStyle // Either .unspecified, .light, or .dark
    // Update your user interface based on the appearance
}

Обнаружение изменений внешнего вида является тривиальным путем переопределения traitCollectionDidChange на контроллерах представления. Затем просто получите доступ к traitCollection.userInterfaceStyle контроллера представления.

Однако важно помнить, что traitCollectionDidChange может вызываться для других изменений свойств, таких как вращение устройства. Вы можете проверить, отличается ли текущий внешний вид, используя этот новый метод:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    let hasUserInterfaceStyleChanged = previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) // Bool
    // Update your user interface based on the appearance
}

в target-c вы хотели бы сделать:

if ( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ){

        //is dark
}else{

    //is light

}

Вы можете использовать это расширение:

import UIKit

extension UIApplication {
    @available(iOS 13.0, *)
    var userInterfaceStyle: UIUserInterfaceStyle? {
        return self.keyWindow?.traitCollection.userInterfaceStyle
    }
}

@available(iOS 13.0, *)
    func setSystemTheme() {
        switch UIApplication.shared.userInterfaceStyle {
        case .dark?:
            currentTheme = .dark
        case .light?:
            currentTheme = .light
        default:
            break
        }
    }

Для iOS 13 вы можете использовать это свойство, чтобы проверить, является ли текущий стиль темным режимом или нет:

if #available(iOS 13.0, *) {
    if UITraitCollection.current.userInterfaceStyle == .dark {
        print("Dark mode")
    }
    else {
        print("Light mode")
    }
}

Это здорово, если вы хотите проверить AppDelegate, так как у него нет переменной traitCollection, такой как UIViewController

Ross Sullivan 12.01.2020 21:37

Спасибо! Наконец-то действительно правильный ответ на проблему AppDelegate :)

itMaxence 30.06.2020 00:40

Это не реагирует на отключенный темный режим. Если вы используете window?.overrideUserInterfaceStyle = .light, то UITraitCollection.current.userInterfaceStyle может вернуться .dark.

Valentin Shamardin 03.08.2020 11:06

Это не работает в моем случае. Сделать мое приложение iOS для Mac поддерживаемым. Текущий внешний вид моего mac mini темный, в файле appdelegate я иногда получаю светлый, а иногда темный режим, а не каждый раз темный режим. Пожалуйста помогите.

Yogendra Patel 29.12.2020 13:40

1/для UIView/UIViewController:

self.traitCollection.userInterfaceStyle == .dark

2/ для статического или другого:

UITraitCollection.current.userInterfaceStyle == .dark

НО:

//Never use this! You will get wrong value in app extensions (ex. ToDay widget)
UIScreen.main.traitCollection.userInterfaceStyle == .dark //WRONG!

На самом деле последний (UIScreen...) был единственным способом получить настройку темного режима пользователя в настройках устройства после переопределения userInterfaceStyle в моем приложении. Таким образом, я смог реализовать кнопку «следить за темным режимом iOS», которая немедленно обновляет цветовую тему приложения, даже если у меня есть пользовательские темы и выбор помимо этого. К сожалению, надежное управление цветом текста строки состояния по отдельности невозможно без переопределения userInterfaceStyle.

nontomatic 23.10.2019 10:22

Обратите внимание, что это может кому-то помочь: если вы установили UIUserInterfaceStyle в light в своем info.plist, эти методы всегда будут возвращать light

Leonid Silver 12.07.2020 22:45

@LeonidSilver Большое спасибо!!! Удалите элемент UIUserInterfaceStyle в info.plist для системной темы (.unspecified), используя!

SBlincov 26.07.2020 21:36

Для меня, используя расширение клавиатуры, UITraitCollection.current.userInterfaceStyle возвращает правильное значение при запуске расширения, но никогда не меняется, когда я включаю и выключаю светлый и темный режимы.

Daniel Saidi 17.07.2021 16:23

Цель С

Чтобы определить, когда темный режим включен или отключен через Центр управления, используйте уведомление «appDidBecomeActive», которое будет запущено, когда вы вернетесь в свое приложение.

//----------------------------------------------------------------------------
//                          viewWillAppear
//----------------------------------------------------------------------------
- (void)viewWillAppear {
    [super viewWillAppear];

    [[NSNotificationCenter defaultCenter]addObserver:self
                                   selector:@selector(appDidBecomeActive:)
                                   name:UIApplicationDidBecomeActiveNotification
                                   object:nil];

}

Не забудьте удалить его, когда закончите:

//------------------------------------------------------------------------------------
//                    viewWillDisappear
//------------------------------------------------------------------------------------
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self        
                                 name:UIApplicationDidBecomeActiveNotification 
                                 object:nil];

}

Делайте все, что вам нужно, когда меняется темный режим:

//----------------------------------------------------------------------------
//                          appDidBecomeActive
//----------------------------------------------------------------------------
-(void)appDidBecomeActive:(NSNotification*)note {
    if (@available(iOS 13.0, *)) {
        if ( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ){
            //dark mode
        }
        else {
            //not dark mode
        }
    }
    else {
        //fall back for older versions
    }
}

Создайте функцию класса для метода записи 1 раз и используйте везде, где хотите

func isDarkMode() -> Bool{
    if #available(iOS 12.0, *) {
        if UIScreen.main.traitCollection.userInterfaceStyle == .dark {
            return true
        } else {
            return false
        }
    } else {
       return false
    }
}  

Для Свифта:

if #available(iOS 12.0, *) {
  switch UIScreen.main.traitCollection.userInterfaceStyle {
    case .dark: // put your dark mode code here
    case .light: 
    case .unspecified: 
  }
}

Для цели C:

if (@available(iOS 12.0, *)) {
        switch (UIScreen.mainScreen.traitCollection.userInterfaceStyle) {
            case UIUserInterfaceStyleDark:
                // put your dark mode code here
                break;
            case UIUserInterfaceStyleLight:
            case UIUserInterfaceStyleUnspecified:
                break;
            default:
                break;
        }
}

Для получения дополнительной информации смотрите этот WWDC2019 видео

В итоге я использовал его для Xamarin.Forms в своем проекте iOS. Безусловно, лучший ответ там. (хороший информированный надежный ответ, работающий лучше, чем сотая копия какого-то блоггера официального документа MS для Xamarin.) @Pedro Trujillo, вы спасли мой день. Спасибо!

Ranndom 30.01.2020 08:23

Любые. иос 11 версия?

famfamfam 02.04.2021 12:49

Может быть, какое-нибудь хорошее расширение?

public extension UIViewController {
    @available(iOS 12.0, *)
    public var isDarkMode: Bool { traitCollection.userInterfaceStyle == .dark }
}

Вспомогательный метод ниже, который работает на любой версии iOS:

var isDarkMode: Bool {
    guard #available(iOS 12.0, *) else {
        return false
    }

    return UIScreen.main.traitCollection.userInterfaceStyle == .dark
}

Применение:

view.backgroundColor = isDarkMode ? .black : .white

Добро пожаловать в Stack Overflow. Дампы кода без каких-либо объяснений редко бывают полезными. Stack Overflow предназначен для обучения, а не для слепого копирования и вставки фрагментов. Пожалуйста, редактировать свой вопрос и объясните, как он работает лучше, чем то, что предоставил OP.

Chris 14.05.2020 02:37

@Крис. Спасибо за комментарий, но буквально каждый ответ здесь — дамп кода... Вопрос очень простой, как и ответ. Спасибо, что указали на это, я добавлю больше объяснений

Lucas Chwe 14.05.2020 14:05

Это не делает ответы только для кода приемлемыми. Этот комментарий был помечен либо как «ответ низкого качества», вероятно, потому, что это был чисто код, либо как «поздний ответ» (я не могу вспомнить какой), и я прокомментировал через очередь проверки. Всегда лучше указать, что вы изменили, почему вы изменили это и как ваш ответ улучшает любые существующие. Я насчитал десять ответов, предшествующих вашим. Сделайте свой выделиться.

Chris 14.05.2020 14:20

Вы можете легко обнаружить темный режим или светлый режим с помощью этого метода Swift 5

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if traitCollection.userInterfaceStyle == .light {
    print("Light mode")
} else {
    print("Dark mode")
}}
Ответ принят как подходящий

SwiftUI

С ключом \.colorScheme переменной Environment:

struct ContentView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text(colorScheme == .dark ? "In dark mode" : "In light mode")
    }
}

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


UIKit

Чтобы проверить текущий, все объекты, соответствующие протоколу UITraitEnvironment, включая все подклассы UIView и все подклассы UIViewConttroller, имеют доступ к текущему стилю:

myUIView.traitCollection.userInterfaceStyle == .dark
myUIViewController.traitCollection.userInterfaceStyle == .dark

Чтобы обнаружить живые изменения стиля, вот полный подробный ответ

Я использовал этот метод в своем ContentView, чтобы изменить цвет акцента интерфейса панели вкладок. В конце представления вкладок я использовал .accentColor(colorScheme == .dark ? .green : .black)

Dave Levy 23.09.2020 23:46

Я получаю Type annotation missing in pattern, когда так объявляю @Enironement.

Ishmael7 13.01.2021 15:52

Вы можете использовать следующий код для проверки светлого или темного режима в вашем проекте:

func viewDidLoad() {
    super.viewDidLoad()

    switch traitCollection.userInterfaceStyle {
        case .light, .unspecified:
            // light mode detected
        case .dark:
            // dark mode detected
    }
}

Вы также можете проверить изменения в стиле интерфейса:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    let userInterfaceStyle = traitCollection.userInterfaceStyle // Either .unspecified, .light, or .dark
    // Update your user interface based on the appearance
}

Как и в macOS начиная с Mojave, вы можете определить изображения как для светлого, так и для темного режима в своем каталоге активов, чтобы эти изображения использовались автоматически:

var isDarkMode: Bool {
    guard #available(iOS 12.0, *) else {
        return false
    }
    let window = (UIApplication.shared.delegate as? AppDelegate)?.window
    return window?.traitCollection.userInterfaceStyle == .dark
}

если вы не используете окно в AppDelegate, вызовите окно из SceneDelegate

Это похоже на большинство ответов выше, но это работает лучше, когда мы меняем режимы, используя

window?.overrideUserInterfaceStyle = .dark

можно назвать как

isDarkMode ? .black : .white

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