Можно ли отказаться от темного режима на iOS 13?

Большая часть моего приложения состоит из веб-представлений, обеспечивающих функциональность, недоступную в нативных реализациях. Веб-команда не планирует внедрять темную тему для веб-сайта. Таким образом, мое приложение будет выглядеть наполовину или наполовину с поддержкой темного режима в iOS 13.

Можно ли отказаться от поддержки темного режима, чтобы наше приложение всегда показывало светлый режим в соответствии с темой веб-сайта?


person SeanR    schedule 11.06.2019    source источник
comment
Установите UIUserInterfaceStyle на Light в вашем Info.Plist. См. developer.apple.com/library/archive/documentation/General/   -  person Tieme    schedule 20.08.2019
comment
Спасибо за вопрос - для всех нас. Множество приложений, которые нужно пройти. Это необходимо, чтобы приложения работали, пока переключатель не будет готов.   -  person user3741598    schedule 27.09.2019
comment
import Foundation import UIKit extension UIViewController {override open func awakeFromNib () {super.awakeFromNib () if #available (iOS 13.0, *) {// Всегда используйте легкий стиль интерфейса. overrideUserInterfaceStyle = .light}}}   -  person Mohammad Razipour    schedule 27.09.2019
comment
просто добавьте UIUserInterfaceStyle в список. это так просто   -  person Fattie    schedule 08.10.2019
comment
При отправке приложения в магазин приложений Apple принимает его из-за UIUserInterfaceStyle в режиме Light.   -  person kiran    schedule 31.10.2019
comment
@kiran - Да, только что сделал это для сборки TF.   -  person benc    schedule 26.05.2020
comment
Я думаю, что мы не можем отключить всплывающие окна с разрешениями и другие системные предупреждения. у кого-нибудь есть решение для этого или это невозможно, потому что os это управляет?   -  person Shrikant Phadke    schedule 13.10.2020


Ответы (29)


Во-первых, здесь запись Apple, касающаяся отказа от темного режима. Содержимое этой ссылки написано для Xcode 11 и iOS 13:

Все приложение через файл info.plist (Xcode 12)

Используйте следующий ключ в вашем файле info.plist:

UIUserInterfaceStyle

И присвойте ему значение Light.

XML для UIUserInterfaceStyle назначения:

<key>UIUserInterfaceStyle</key>
<string>Light</string>

Документация Apple для UIUserInterfaceStyle


Все приложение через info.plist в настройках сборки (Xcode 13)

введите описание изображения здесь


Окно всего приложения через свойство окна

Вы можете установить overrideUserInterfaceStyle напротив переменной приложения window. Это будет применяться ко всем представлениям, которые появляются в окне. Это стало доступно в iOS 13, поэтому для приложений, поддерживающих предыдущие версии, вы должны включить проверку доступности.

В зависимости от того, как был создан ваш проект, он может находиться в файле AppDelegate или SceneDelegate.

if #available(iOS 13.0, *) {
    window?.overrideUserInterfaceStyle = .light
}

Индивидуальный UIViewController или UIView

Вы можете установить overrideUserInterfaceStyle напротив переменной UIViewControllers или UIView overrideUserInterfaceStyle. Это стало доступно в iOS 13, поэтому для приложений, поддерживающих предыдущие версии, вы должны включить проверку доступности.

Быстрый

override func viewDidLoad() {
    super.viewDidLoad()
    // overrideUserInterfaceStyle is available with iOS 13
    if #available(iOS 13.0, *) {
        // Always adopt a light interface style.
        overrideUserInterfaceStyle = .light
    }
}

Для тех бедняжек в Objective-C

if (@available(iOS 13.0, *)) {
        self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}

Когда установлено против UIViewController, контроллер представления и его дочерние элементы принимают определенный режим.

Когда установлено против UIView, представление и его дочерние элементы принимают определенный режим.

Документация Apple по overrideUserInterfaceStyle


Индивидуальные представления через SwiftUI View

Вы можете установить preferredColorScheme равным light или dark. Указанное значение установит цветовую схему для презентации.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Light Only")
            .preferredColorScheme(.light)
    }
}

Документация Apple для PreferredColorScheme


Благодарим @Aron Nelson, @Raimundas Sakalauskas, @NSLeader и @rmaddy за улучшение этого ответа благодаря их отзывам. .

person CodeBender    schedule 11.06.2019
comment
UIUserInterfaceStyle свет сейчас заблокирован при обновлении / загрузке вашего приложения. Он помечается как недопустимая запись в списке. (Неверный ключ списка) - person Aron Nelson; 15.08.2019
comment
Это не будет компилироваться с iOS SDK 12 (в настоящее время последний стабильный SDK). См. stackoverflow.com/a/57521901/2249485 для решения, которое также будет работать с iOS 12 SDK. - person Raimundas Sakalauskas; 16.08.2019
comment
Это настолько несправедливо, что вопрос, который имеет гораздо больше просмотров, чем исходный вопрос, заблокирован для предоставления ответов. :( - person Raimundas Sakalauskas; 18.09.2019
comment
Я только что загрузил запись .plist, и она прошла ... очень интересно, как это будет воспринято в обзоре ... хммм - person thisIsTheFoxe; 19.09.2019
comment
Вместо того, чтобы устанавливать overrideUserInterfaceStyle в viewDidLoad каждого контроллера представления, вы можете установить его один раз в главном окне приложения. Намного проще, если вы хотите, чтобы все приложение работало одинаково. - person rmaddy; 19.09.2019
comment
Я предполагаю, что указанная выше ошибка App Store была ошибкой со стороны Apple. Я только что загрузил приложение сегодня с этим ключом plist, и оно прошло нормально. - person Bek; 24.09.2019
comment
Xcode 11.0 (11A420a) загружен из магазина приложений (не GM seed). - person Bek; 24.09.2019
comment
@Bek Хорошо, извините, я не сказал об этом явно, но это сообщение об ошибке относится только к Xcode 10. - person CodeBender; 24.09.2019
comment
Используйте #if compiler(>=5.1) вместо responds(to:) и setValue - person NSLeader; 24.09.2019
comment
как насчет стиля строки состояния? он показывает белый цвет в темном режиме - person Rohit Funde; 01.10.2019
comment
@thisIsTheFoxe Есть обновления? Мне любопытно, могу ли я использовать это для наших живых приложений, поскольку у нас пока нет планов по его поддержке, а некоторые части нашего приложения «ломаются», например tableViews получает темный фон, в то время как текст также темный. - person Jeroen; 04.10.2019
comment
@JeroenJK Я думаю, с тобой все будет в порядке. Если вы посмотрите, у вас также должна быть возможность отказаться прямо из раскадровки, поэтому не должно быть невозможным пройти AS-Review. Но вы обязательно должны это учитывать - имо :) - person thisIsTheFoxe; 04.10.2019
comment
Да, я успешно развернул новые версии наших приложений. :-) - person Jeroen; 10.10.2019
comment
Я попытался изменить все приложение с помощью xcode 10.5. Но полученный функционально-подобный макрос "компилятор" не определен. - person 7xRobin; 12.12.2019
comment
Ключ в Info.plist изменился на Appearance. <key> Appearance</key> <string>Light</string> - person huync; 18.03.2021
comment
В более новых версиях Info.plist добавляет Appearance: Light / Dark - person Amit Khetan; 31.03.2021

Согласно сеансу Apple «Внедрение темного режима в iOS» (https://developer.apple.com/videos/play/wwdc2019/214/, начиная с 31:13) можно установить overrideUserInterfaceStyle на UIUserInterfaceStyleLight или UIUserInterfaceStyleDark на любом контроллере представления или представлении, которое будет использоваться в traitCollection для любого подпредставления или просмотр контроллера.

Как уже упоминалось SeanR, вы можете установить UIUserInterfaceStyle на Light или Dark в файле plist вашего приложения, чтобы изменить это для всего вашего приложения.

person dorbeetle    schedule 11.06.2019
comment
Если вы установите ключ UIUserInterfaceStyle, ваше приложение будет отклонено в магазине приложений. - person Sonius; 20.08.2019
comment
Apple отклонила с кодом ошибки ITMS-90190 forum.developer.apple.com/thread/121028 - person PRASAD1240; 20.08.2019
comment
Отклонение, скорее всего, произойдет из-за того, что iOS 13 SDK еще не вышел из бета-версии. Я думаю, это должно сработать, как только появится Xcode 11 GM. - person dorbeetle; 21.08.2019
comment
@dorbeetle, это неправда, я успешно загрузил свое приложение с этим ключом, как 1 месяц назад, с помощью Xcode 10. Отказы произошли недавно. Кажется, это какая-то новая стратегия Apple. - person steven; 28.08.2019
comment
Странно слышать об отказе. Что касается документации ios 13, в нем говорится, что установите ключ UIUserInterfaceStyle в свой Info.plist. - person dpart; 05.09.2019
comment
Это все еще происходит. Xcode GM2 вернул ошибку подписи приложения. Xcode 10.3 вернул: недопустимый ключ Info.plist. Ключ UIUserInterfaceStyle в файле Payload / Galileo.appInfo.plist недействителен. - person Evgen Bodunov; 20.09.2019

Если вы не используете Xcode 11 или новее (например, SDK для iOS 13 или новее), ваше приложение не выбрало автоматически поддержку темного режима. Таким образом, нет необходимости отказываться от темного режима.

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

Полностью отключите темный режим для своего приложения

Вы можете отключить темный режим, включив ключ UIUserInterfaceStyle со значением Light в файл Info.plist вашего приложения.
 UIUserInterfaceStyle as Light
Это игнорирует предпочтения пользователя и всегда применяет светлый вид в ваше приложение.

Отключить темный режим для окна, представления или контроллера представления

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

Посмотреть контроллеры:

override func viewDidLoad() {
    super.viewDidLoad()
    /* view controller’s views and child view controllers 
     always adopt a light interface style. */
    overrideUserInterfaceStyle = .light
}

Просмотры:

// The view and all of its subviews always adopt light style.
youView.overrideUserInterfaceStyle = .light

Окно:

/* Everything in the window adopts the style, 
 including the root view controller and all presentation controllers that 
 display content in that window.*/
window.overrideUserInterfaceStyle = .light

Примечание. Apple настоятельно рекомендует поддерживать темный режим в вашем приложении. Таким образом, вы можете временно отключить темный режим.

Подробнее читайте здесь: Выбор конкретного стиля интерфейса для вашего приложения iOS

person Ajith R Nayak    schedule 23.09.2019
comment
В XCode 12.4 он отображался как внешний вид, а не как стиль пользовательского интерфейса. - person CSchwarz; 29.04.2021

********** Самый простой способ для Xcode 11 и выше ***********

Добавьте это в info.plist перед </dict></plist>

<key>UIUserInterfaceStyle</key>
<string>Light</string>
person Kingsley Mitchell    schedule 08.10.2019
comment
это решение не сработает при отправке приложения на Xcode 10.x - person Tawfik Bouabid; 23.10.2019

Думаю, я нашел решение. Сначала я собрал его по кусочкам из UIUserInterfaceStyle - Information Property List и UIUserInterfaceStyle - UIKit, но теперь мы обнаружили, что это фактически задокументировано на Выбор определенного стиля интерфейса для вашего приложения iOS.

В вашем info.plist установите для UIUserInterfaceStyle (Стиль пользовательского интерфейса) значение 1 (_ 3_).

РЕДАКТИРОВАТЬ: Согласно ответу дорбита, более подходящей настройкой для UIUserInterfaceStyle может быть Light.

person SeanR    schedule 11.06.2019
comment
Однако включение темного режима путем установки значения 2 не работает: [UIInterfaceStyle] '2' is not a recognized value for UIUserInterfaceStyle. Defaulting to Light. - person funkenstrahlen; 11.06.2019
comment
Наличие этого ключа в списке приведет к отклонению App Store. - person José; 20.08.2019
comment
AppStore больше не отклоняет это свойство в plist.info. Я поставил Dark (с заглавной буквы), так как наше приложение уже темное. Нет проблем. Это позволяет нам правильно использовать системные элементы управления. - person nickdnk; 25.09.2019
comment
@nickdnk Я думаю, вы создали свое приложение с помощью Xcode 11, рекомендованного Apple. - person DawnSong; 26.09.2019
comment
Да. Это не меняет того факта, что Apple действительно принимает этот параметр в plist, что я и пытался прояснить. - person nickdnk; 26.09.2019
comment
Я пробовал установить LIGHT, Light, light, .light, 1 - все то же самое - не работает. Xcode: версия 11.3.1 (11C504) - person Andrew; 16.01.2020

Обновление Xcode 12 и iOS 14. Я попробовал предыдущие варианты отключения темного режима, и это предложение в файле info.plist у меня не работает:

<key>UIUserInterfaceStyle</key>
<string>Light</string>

Теперь он переименован в:

<key>Appearance</key>
<string>Light</string>

Этот параметр заблокирует все темные режимы в полном приложении.

ИЗМЕНИТЬ:

Исправлена ​​опечатка, спасибо @sarah

person wazowski    schedule 22.09.2020
comment
небольшая опечатка, это должно быть Внешний вид :) - person sarah; 06.11.2020
comment
Фиксированный! Спасибо @Sarah :) - person wazowski; 06.11.2020
comment
Рабочее и обновленное решение - person Naveed Ahmad; 03.01.2021
comment
Лучший ответ, спасибо! - person Leon Jakonda; 13.05.2021

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

Если вы компилируете iOS 13 SDK, вы можете просто использовать следующий код:

Быстрый:

if #available(iOS 13.0, *) {
    self.overrideUserInterfaceStyle = .light
}

Obj-C:

if (@available(iOS 13.0, *)) {
    self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}

ОДНАКО, если вы хотите, чтобы ваш код также компилировался с iOS 12 SDK (который на данный момент все еще является последним стабильным SDK), вам следует прибегнуть к использованию селекторов. Код с селекторами:

Swift (XCode покажет предупреждения для этого кода, но пока это единственный способ сделать это, поскольку свойство не существует в SDK 12, поэтому не будет компилироваться):

if #available(iOS 13.0, *) {
    if self.responds(to: Selector("overrideUserInterfaceStyle")) {
        self.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
    }
}

Obj-C:

if (@available(iOS 13.0, *)) {
    if ([self respondsToSelector:NSSelectorFromString(@"overrideUserInterfaceStyle")]) {
        [self setValue:@(UIUserInterfaceStyleLight) forKey:@"overrideUserInterfaceStyle"];
    }
}
person Raimundas Sakalauskas    schedule 16.08.2019
comment
Будет лучше, если вы укажете, к чему принадлежит свойство overrideUserInterfaceStyle. - person DawnSong; 26.09.2019

Вы можете отключить темный режим во всем приложении в Xcode 11:

  1. Перейти в Info.plist
  2. Добавить ниже как

    <key>UIUserInterfaceStyle</key>
    <string>Light</string>
    

Info.plist будет выглядеть так, как показано ниже ...

введите описание изображения здесь

person Enamul Haque    schedule 26.11.2019
comment
по какой-то причине не работает для Xcode версии 11.3.1 (11C504) - person Andrew; 16.01.2020

Последнее обновление-

Если вы используете Xcode 10.x, то по умолчанию UIUserInterfaceStyle это light для iOS 13.x. При запуске на устройстве iOS 13 он будет работать только в облегченном режиме.

Нет необходимости явно добавлять ключ UIUserInterfaceStyle в файл Info.plist, его добавление приведет к ошибке при проверке приложения, например:

Неверный ключ Info.plist. Ключ UIUserInterfaceStyle в файле Payload / AppName.appInfo.plist недействителен.

Добавляйте ключ UIUserInterfaceStyle в файл Info.plist только при использовании Xcode 11.x.

person kumarsiddharth123    schedule 13.09.2019
comment
Это не имеет ничего общего с Xcode 10 или 11. Если пользователь развертывает приложение из Xcode 10 и не заботится о темном режиме, приложение при установке на iPhone 11, Pro или Pro Max будет иметь проблемы с темным режимом. вам необходимо выполнить обновление до Xcode 11 и решить эту проблему. - person Niranjan Molkeri; 16.09.2019
comment
@NiranjanMolkeri Это не имеет ничего общего с новыми iPhone. Речь идет о темном режиме на iOS 13. В предыдущих приложениях бета-версии iOS 13 пользовательский интерфейс имел проблемы с темным режимом, если не обрабатывались явно. Но в последней версии это исправлено. Если вы используете XCode 10, то UIUserInterfaceStyle по умолчанию для iOS13 является легким. Если вы используете Xode11, вам нужно с этим справиться. - person kumarsiddharth123; 17.09.2019
comment
У вас возникнут проблемы, если вы загрузите приложение в TestFligth с помощью Xcode 10.3, а список включает ключ UIUserInterfaceStyle. Он скажет, что это недопустимый файл plist. Вам нужно либо удалить его, если вы строите в Xcode 10, либо загружаете с помощью Xcode 11. - person eharo2; 23.10.2019

Для всего приложения: (в файле info.plist):

<key>UIUserInterfaceStyle</key>
<string>Light</string>

plist


Окно (обычно все приложение):

window!.overrideUserInterfaceStyle = .light

Вы можете получить окно с SceneDelegate


UIViewController:

viewController.overrideUserInterfaceStyle = .light

Вы можете установить любой viewController, даже внутри viewController, это self


UIView:

view.overrideUserInterfaceStyle = .light

Вы можете установить любой view, даже внутри вида, это само

Возможно, вам придется использовать if #available(iOS 13.0, *) { ,,, }, если вы поддерживаете более ранние версии iOS.


Просмотр SwiftUI:

.preferredColorScheme(.light) <- This Modifier

or

.environment(\.colorScheme, .light) <- This Modifier
person Mojtaba Hosseini    schedule 20.09.2019

Если вы добавите ключ UIUserInterfaceStyle в файл plist, возможно, Apple отклонит сборку выпуска, как указано здесь: https://stackoverflow.com/a/56546554/7524146 В любом случае явно раздражает каждый ViewController self.overrideUserInterfaceStyle = .light. Но вы можете один раз использовать этот кусок кода для корневого window объекта:

if #available(iOS 13.0, *) {
    if window.responds(to: Selector(("overrideUserInterfaceStyle"))) {
        window.setValue(UIUserInterfaceStyle.light.rawValue, forKey: "overrideUserInterfaceStyle")
    }
}

Просто обратите внимание, что вы не можете сделать это внутри application(application: didFinishLaunchingWithOptions:), потому что этот селектор не будет отвечать true на этой ранней стадии. Но вы можете сделать это позже. Это очень просто, если вы используете собственный класс AppPresenter или AppRouter в своем приложении вместо автоматического запуска пользовательского интерфейса в AppDelegate.

person SerhiiK    schedule 21.08.2019

Обновление iOS 14.3 и Xcode 12.3

В файле info.plist добавьте Внешний вид как Светлый.

<key>Appearance</key>
<string>Light</string>
person alvin    schedule 21.12.2020
comment
не работал на симуляторе - person Yodagama; 23.12.2020
comment
@Yodagama, пожалуйста, проверьте версию своего симулятора iOS и версию Xcode. Он должен работать нормально, я только что протестировал его на своем симуляторе. - person alvin; 23.12.2020
comment
Я делал на xcode 12.1 и ios 14.2 - person Yodagama; 23.12.2020
comment
Он отлично работает в Xcode 12.3 и iOS 14.3. Для вашей версии попробуйте следующее ‹key› UIUserInterfaceStyle ‹/key› ‹string› Light ‹/string› - person alvin; 23.12.2020

Помимо других ответов, насколько я понимаю, вам нужно подготовиться только к темному режиму при компиляции с iOS 13 SDK (с использованием XCode 11).

Система предполагает, что приложения, связанные с iOS 13 или более поздней версией SDK, поддерживают как светлый, так и темный вид. В iOS вы указываете конкретный внешний вид, который хотите, назначая определенный стиль интерфейса вашему окну, представлению или контроллеру представления. Вы также можете полностью отключить поддержку темного режима с помощью ключа Info.plist.

Ссылка

person Claudio    schedule 10.09.2019

Swift 5

Два способа переключить темный режим на светлый:

1- info.plist

    <key>UIUserInterfaceStyle</key>
    <string>Light</string>

2- Программно или во время выполнения

  @IBAction private func switchToDark(_ sender: UIButton){
        UIApplication.shared.windows.forEach { window in
            //here you can switch between the dark and light
            window.overrideUserInterfaceStyle = .dark
        }
    }
person Rashid Latif    schedule 05.05.2020

На данный момент мое приложение не поддерживает темный режим и использует светлый цвет панели приложений. Мне удалось заставить содержимое строки состояния сделать темный текст и значки, добавив следующий ключ к моему Info.plist:

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDarkContent</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>

Найдите другие возможные значения здесь: https://developer.apple.com/documentation/uikit/uistatusbarstyle

Пользователи Flutter

Не забудьте установить атрибут яркости панели приложения на панели приложения Flutter следующим образом:

AppBar(
    backgroundColor: Colors.grey[100],
    brightness: Brightness.light, // <---------
    title: const Text('Hi there'),
),
person ToniTornado    schedule 30.09.2019

Да, вы можете пропустить, добавив следующий код в viewDidLoad:

if #available(iOS 13.0, *) {
        // Always adopt a light interface style.
        overrideUserInterfaceStyle = .light
    }
person Muhammad Naeem Paracha    schedule 26.09.2019

Objective-c версия

 if (@available(iOS 13.0, *)) {
        _window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
person ahbou    schedule 21.02.2020

В Xcode 12 вы можете изменить добавление в качестве внешнего вида. Это будет работать !!

person vishnu hari    schedule 05.11.2020

Добавить в info.plist

<key>UIUserInterfaceStyle</key>
    <string>Light</string>
person Menon Hasan    schedule 21.12.2020

Вот несколько советов и приемов, которые вы можете использовать в своем приложении для поддержки или обхода темного режима.

Первый совет: переопределить стиль ViewController

вы можете переопределить стиль интерфейса UIViewController с помощью

1: overrideUserInterfaceStyle = .dark // Для темного режима

2: overrideUserInterfaceStyle = .light // Для светового режима

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        overrideUserInterfaceStyle = .light    
    }
}

Второй совет: добавление ключа в info.plist

Просто вы можете добавить новый ключ

UIUserInterfaceStyle

в вашем приложении info.plist и установите для него значение Светлый или Темный. это заменит стиль приложения по умолчанию на указанное вами значение. Вам не нужно добавлять overrideUserInterfaceStyle = .light эту строку в каждый viewController, достаточно одной строки в info.plist.

person Mohammed Ebrahim    schedule 12.11.2019

Просто добавьте следующий ключ в свой info.plist файл:

<key>UIUserInterfaceStyle</key>
    <string>Light</string>
person Moeen Ahmad    schedule 25.11.2019

Просто добавьте эту строку в файл info.plist:

<key>UIUserInterfaceStyle</key>
<string>light</string>

Это заставит приложение работать только в облегченном режиме.

person Rahul Gusain    schedule 18.12.2019
comment
Об этом уже много раз комментировали и отвечали. Об этом свидетельствует даже принятый ответ. Поэтому этот комментарий не добавляет никакой новой информации. - person Jeroen; 18.12.2019

Да .. вы можете добавить настройку ниже в проект iOS.

В файле info.plist добавьте UIUserInterfaceStyle в Light.

Если ваш проект находится в IONIC .. Вы можете добавить настройки ниже в файл конфигурации

<platform name="ios">
  <edit-config file="*-Info.plist" mode="merge" target="UIUserInterfaceStyle">
  <string>Light</string>
 </edit-config>
</platform>

Используя эти настройки, темный режим устройства не повлияет на ваше приложение.

person rakesh    schedule 18.03.2021

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

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

      if #available(iOS 13.0, *) {
          UIWindow.appearance().overrideUserInterfaceStyle = .light
      }

      return true
    }
}
person Dmitry    schedule 12.11.2019

Вы можете сделать: добавить этот новый ключ UIUserInterfaceStyle в Info.plist и установить для него значение Light. и проверьте, что контроллер предупреждений появляется в световом режиме.

UIUserInterfaceStyle Light Если вы включили светлый / темный режим во всем приложении независимо от настроек пользователя, добавив ключ UIUserInterfaceStyle в ваш файл Info.plist и установив для него значение Light или Dark.

person HomiFox    schedule 10.04.2020

На этот вопрос так много ответов, поэтому, используя его в info.plist, вы можете задать его в AppDelegate следующим образом:

#if compiler(>=5.1)
        if #available(iOS 13.0, *) {
            self.window?.overrideUserInterfaceStyle = .light
        }
        #endif

Тест на Xcode 11.3, iOS 13.3

person Niraj    schedule 13.04.2020

На самом деле я просто написал код, который позволит вам глобально отказаться от темного режима в коде без необходимости путаться с каждым отдельным контроллером viw в вашем приложении. Вероятно, это можно улучшить, чтобы отказаться от класса за классом, управляя списком классов. Что касается меня, то я хочу, чтобы мои пользователи видели, нравится ли им интерфейс темного режима для моего приложения, и, если он им не нравится, они могут его отключить. Это позволит им продолжать использовать темный режим для остальных своих приложений.

Выбор пользователя - это хорошо (кхм, глядя на вас, Apple, вот как вы должны были это реализовать).

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

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

Я еще не написал ничего, чтобы ответить пользователю, включающим или выключающим флаг. Итак, это в основном пример кода. Если мы хотим, чтобы пользователь взаимодействовал с этим, необходимо перезагрузить все контроллеры представления. Я не знаю, как это сделать навскидку, но, вероятно, отправка какого-нибудь уведомления поможет. Итак, сейчас это глобальное включение / выключение темного режима будет работать только при запуске или перезапуске приложения.

Теперь недостаточно просто попытаться отключить темный режим в каждом отдельном контроллере просмотра MFING в вашем огромном приложении. Если вы используете цветные ассеты, вы полностью разочарованы. Мы уже более 10 лет понимаем, что неизменяемые объекты являются неизменяемыми. Цвета, которые вы получаете из каталога цветовых ресурсов, говорят, что они являются UIColor, но они являются динамическими (изменяемыми) цветами и будут меняться под вами, когда система переходит из темного режима в светлый. Это должна быть особенность. Но, конечно, нет главного переключателя, чтобы попросить эти вещи прекратить вносить это изменение (насколько я знаю прямо сейчас, может быть, кто-то сможет это улучшить).

Итак, решение состоит из двух частей:

  1. общедоступная категория в UIViewController, которая предоставляет некоторые полезные и удобные методы ... например, я не думаю, что Apple задумывалась о том, что некоторые из нас добавляют веб-код в наши приложения. Таким образом, у нас есть таблицы стилей, которые необходимо переключать в зависимости от темного или светлого режима. Таким образом, вам нужно либо создать какой-то объект динамической таблицы стилей (что было бы хорошо), либо просто спросить, каково текущее состояние (плохо, но легко).

  2. эта категория при загрузке заменит метод viewDidLoad класса UIViewController и перехватит вызовы. Я не знаю, нарушает ли это правила магазина приложений. Если это так, вероятно, есть другие способы обойти это, но вы можете считать это доказательством концепции. Вы можете, например, создать один подкласс всех основных типов контроллеров представления и сделать так, чтобы все ваши собственные контроллеры представления унаследовали от них, а затем вы можете использовать идею категории DarkMode и вызвать ее, чтобы принудительно отказаться от всех ваших контроллеров представления. Он уродливее, но никаких правил нарушать не собирается. Я предпочитаю использовать среду выполнения, потому что она была создана для этого. Итак, в моей версии вы просто добавляете категорию, вы устанавливаете глобальную переменную в категории для того, хотите ли вы, чтобы она блокировала темный режим, и она это сделает.

  3. Вы еще не вышли из леса, как уже упоминалось, другая проблема заключается в том, что UIColor в основном делает все, что, черт возьми, хочет. Таким образом, даже если ваши контроллеры представления блокируют темный режим, UIColor не знает, где и как вы его используете, поэтому не может адаптироваться. В результате вы можете получить его правильно, но потом он вернется к вам в какой-то момент в будущем. Может, скоро, может, позже. Чтобы решить эту проблему, дважды выделите его с помощью CGColor и превратите в статический цвет. Это означает, что если ваш пользователь вернется и снова включит темный режим на вашей странице настроек (идея состоит в том, чтобы сделать эту работу так, чтобы пользователь мог контролировать ваше приложение над остальной системой), все эти статические цвета нужно заменить. Пока этот вопрос решает кто-то другой. Самый простой способ сделать это - установить по умолчанию, что вы отказываетесь от темного режима, разделить на ноль, чтобы вывести приложение из строя, поскольку вы не можете выйти из него, и попросить пользователя просто перезапустить его. Это, вероятно, также нарушает правила магазина приложений, но это идея.

Категория UIColor не нуждается в раскрытии, она просто работает, вызывая colorNamed: ... если вы не указали классу DarkMode ViewController блокировать темный режим, он будет работать идеально, как и ожидалось. Попытка сделать что-то элегантное вместо стандартного кода яблочного сфагетти, что означает, что вам придется изменить большую часть своего приложения, если вы хотите программно отказаться от темного режима или переключить его. Теперь я не знаю, есть ли лучший способ программно изменить Info.plist, чтобы отключить темный режим по мере необходимости. Насколько я понимаю, это функция времени компиляции, и после этого вас ждут.

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

Честно предупреждаю, что я не использую ARC или какие-либо другие методы удержания рук.

////// H file

#import <UIKit/UIKit.h>

@interface UIViewController(DarkMode)

// if you want to globally opt out of dark mode you call these before any view controllers load
// at the moment they will only take effect for future loaded view controllers, rather than currently
// loaded view controllers

// we are doing it like this so you don't have to fill your code with @availables() when you include this
typedef enum {
    QOverrideUserInterfaceStyleUnspecified,
    QOverrideUserInterfaceStyleLight,
    QOverrideUserInterfaceStyleDark,
} QOverrideUserInterfaceStyle;

// the opposite condition is light interface mode
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)override;
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;

// utility methods
// this will tell you if any particular view controller is operating in dark mode
- (BOOL)isUsingDarkInterfaceStyle;
// this will tell you if any particular view controller is operating in light mode mode
- (BOOL)isUsingLightInterfaceStyle;

// this is called automatically during all view controller loads to enforce a single style
- (void)tryToOverrideUserInterfaceStyle;

@end


////// M file


//
//  QDarkMode.m

#import "UIViewController+DarkMode.h"
#import "q-runtime.h"


@implementation UIViewController(DarkMode)

typedef void (*void_method_imp_t) (id self, SEL cmd);
static void_method_imp_t _nativeViewDidLoad = NULL;
// we can't @available here because we're not in a method context
static long _override = -1;

+ (void)load;
{
#define DEFAULT_UI_STYLE UIUserInterfaceStyleLight
    // we won't mess around with anything that is not iOS 13 dark mode capable
    if (@available(iOS 13,*)) {
        // default setting is to override into light style
        _override = DEFAULT_UI_STYLE;
        /*
         This doesn't work...
        NSUserDefaults *d = NSUserDefaults.standardUserDefaults;
        [d setObject:@"Light" forKey:@"UIUserInterfaceStyle"];
        id uiStyle = [d objectForKey:@"UIUserInterfaceStyle"];
        NSLog(@"%@",uiStyle);
         */
        if (!_nativeViewDidLoad) {
            Class targetClass = UIViewController.class;
            SEL targetSelector = @selector(viewDidLoad);
            SEL replacementSelector = @selector(_overrideModeViewDidLoad);
            _nativeViewDidLoad = (void_method_imp_t)QMethodImplementationForSEL(targetClass,targetSelector);
            QInstanceMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
        }
    }
}

// we do it like this because it's not going to be set often, and it will be tested often
// so we can cache the value that we want to hand to the OS
+ (void)setOverrideUserInterfaceMode:(QOverrideUserInterfaceStyle)style;
{
    if (@available(iOS 13,*)){
        switch(style) {
            case QOverrideUserInterfaceStyleLight: {
                _override = UIUserInterfaceStyleLight;
            } break;
            case QOverrideUserInterfaceStyleDark: {
                _override = UIUserInterfaceStyleDark;
            } break;
            default:
                /* FALLTHROUGH - more modes can go here*/
            case QOverrideUserInterfaceStyleUnspecified: {
                _override = UIUserInterfaceStyleUnspecified;
            } break;
        }
    }
}
+ (QOverrideUserInterfaceStyle)overrideUserInterfaceMode;
{
    if (@available(iOS 13,*)){
        switch(_override) {
            case UIUserInterfaceStyleLight: {
                return QOverrideUserInterfaceStyleLight;
            } break;
            case UIUserInterfaceStyleDark: {
                return QOverrideUserInterfaceStyleDark;
            } break;
            default:
                /* FALLTHROUGH */
            case UIUserInterfaceStyleUnspecified: {
                return QOverrideUserInterfaceStyleUnspecified;
            } break;
        }
    } else {
        // we can't override anything below iOS 12
        return QOverrideUserInterfaceStyleUnspecified;
    }
}

- (BOOL)isUsingDarkInterfaceStyle;
{
    if (@available(iOS 13,*)) {
        if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark){
            return YES;
        }
    }
    return NO;
}

- (BOOL)isUsingLightInterfaceStyle;
{
    if (@available(iOS 13,*)) {
        if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight){
            return YES;
        }
        // if it's unspecified we should probably assume light mode, esp. iOS 12
    }
    return YES;
}

- (void)tryToOverrideUserInterfaceStyle;
{
    // we have to check again or the compile will bitch
    if (@available(iOS 13,*)) {
        [self setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)_override];
    }
}

// this method will be called via the viewDidLoad chain as we will patch it into the
// UIViewController class
- (void)_overrideModeViewDidLoad;
{
    if (_nativeViewDidLoad) {
        _nativeViewDidLoad(self,@selector(viewDidLoad));
    }
    [self tryToOverrideUserInterfaceStyle];
}


@end

// keep this in the same file, hidden away as it needs to switch on the global ... yeah global variables, I know, but viewDidLoad and colorNamed: are going to get called a ton and already it's adding some inefficiency to an already inefficient system ... you can change if you want to make it a class variable. 

// this is necessary because UIColor will also check the current trait collection when using asset catalogs
// so we need to repair colorNamed: and possibly other methods
@interface UIColor(DarkMode)
@end

@implementation UIColor (DarkMode)

typedef UIColor *(*color_method_imp_t) (id self, SEL cmd, NSString *name);
static color_method_imp_t _nativeColorNamed = NULL;
+ (void)load;
{
    // we won't mess around with anything that is not iOS 13 dark mode capable
    if (@available(iOS 13,*)) {
        // default setting is to override into light style
        if (!_nativeColorNamed) {
            // we need to call it once to force the color assets to load
            Class targetClass = UIColor.class;
            SEL targetSelector = @selector(colorNamed:);
            SEL replacementSelector = @selector(_overrideColorNamed:);
            _nativeColorNamed = (color_method_imp_t)QClassMethodImplementationForSEL(targetClass,targetSelector);
            QClassMethodOverrideFromClass(targetClass, targetSelector, targetClass, replacementSelector);
        }
    }
}


// basically the colors you get
// out of colorNamed: are dynamic colors... as the system traits change underneath you, the UIColor object you
// have will also change since we can't force override the system traits all we can do is force the UIColor
// that's requested to be allocated out of the trait collection, and then stripped of the dynamic info
// unfortunately that means that all colors throughout the app will be static and that is either a bug or
// a good thing since they won't respond to the system going in and out of dark mode
+ (UIColor *)_overrideColorNamed:(NSString *)string;
{
    UIColor *value = nil;
    if (@available(iOS 13,*)) {
        value = _nativeColorNamed(self,@selector(colorNamed:),string);
        if (_override != UIUserInterfaceStyleUnspecified) {
            // the value we have is a dynamic color... we need to resolve against a chosen trait collection
            UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_override];
            value = [value resolvedColorWithTraitCollection:tc];
        }
    } else {
        // this is unreachable code since the method won't get patched in below iOS 13, so this
        // is left blank on purpose
    }
    return value;
}
@end

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

// q-runtime.h

#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <stdatomic.h>

// returns the method implementation for the selector
extern IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector);

// as above but gets class method
extern IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector);


extern BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                              Class replacementClass, SEL replacementSelector);

extern BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                                 Class replacementClass, SEL replacementSelector);


// q-runtime.m

static BOOL
_QMethodOverride(Class targetClass, SEL targetSelector, Method original, Method replacement)
{
    BOOL flag = NO;
    IMP imp = method_getImplementation(replacement);
    // we need something to work with
    if (replacement) {
        // if something was sitting on the SEL already
        if (original) {
            flag = method_setImplementation(original, imp) ? YES : NO;
            // if we're swapping, use this
            //method_exchangeImplementations(om, rm);
        } else {
            // not sure this works with class methods...
            // if it's not there we want to add it
            flag = YES;
            const char *types = method_getTypeEncoding(replacement);
            class_addMethod(targetClass,targetSelector,imp,types);
            XLog_FB(red,black,@"Not sure this works...");
        }
    }
    return flag;
}

BOOL
QInstanceMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                                 Class replacementClass, SEL replacementSelector)
{
    BOOL flag = NO;
    if (targetClass && replacementClass) {
        Method om = class_getInstanceMethod(targetClass,targetSelector);
        Method rm = class_getInstanceMethod(replacementClass,replacementSelector);
        flag = _QMethodOverride(targetClass,targetSelector,om,rm);
    }
    return flag;
}


BOOL
QClassMethodOverrideFromClass(Class targetClass, SEL targetSelector,
                              Class replacementClass, SEL replacementSelector)
{
    BOOL flag = NO;
    if (targetClass && replacementClass) {
        Method om = class_getClassMethod(targetClass,targetSelector);
        Method rm = class_getClassMethod(replacementClass,replacementSelector);
        flag = _QMethodOverride(targetClass,targetSelector,om,rm);
    }
    return flag;
}

IMP
QMethodImplementationForSEL(Class aClass, SEL aSelector)
{
    Method method = class_getInstanceMethod(aClass,aSelector);
    if (method) {
        return method_getImplementation(method);
    } else {
        return NULL;
    }
}

IMP
QClassMethodImplementationForSEL(Class aClass, SEL aSelector)
{
    Method method = class_getClassMethod(aClass,aSelector);
    if (method) {
        return method_getImplementation(method);
    } else {
        return NULL;
    }
}

Я копирую и вставляю это из пары файлов, поскольку q-runtime.h - моя многоразовая библиотека, и это лишь ее часть. Если что-то не компилируется, дайте мне знать.

person dbquarrel    schedule 08.07.2019
comment
Вам не повезло, когда дело доходит до управления поведением UIColor, как обсуждается в этом вопросе: stackoverflow.com/questions/56487679 / - person raven_raven; 05.09.2019

person    schedule
comment
Не могли бы вы немного объяснить, как этот ответ решит проблему, вместо того, чтобы публиковать ответ только с кодом. - person Arun Vinoth; 26.12.2019
comment
Да, конечно, @ArunVinoth В IOS 13 введен темный режим, поэтому, если ваша цель развертывания ниже 13, используйте приведенный выше код, иначе вы можете использовать простой оператор, написанный в блоке if. - person Talha Rasool; 27.12.2019

person    schedule
comment
Пожалуйста, добавьте пояснение к своему ответу, отредактировав его, чтобы другие могли извлечь из него уроки. - person Nico Haase; 07.04.2020