Поддержка темной темы: адаптация вашего приложения для поддержки темной темы

Туториалы

Поддержка темной темы: адаптация вашего приложения для поддержки темной темы

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

Когда Apple представила современный и плоский дизайн iOS7 в 2013 году, многие люди возражали против чрезмерной белизны его пользовательского интерфейса. Они предпочитали более естественные варианты предыдущих версий iOS.

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

К счастью, в iOS 13 Apple решила предоставить этой функции любовь системного уровня. Инженеры Apple добавили переключатель для пользователей, чтобы переключаться между светлым и темным внешним видом. Они также обновили все предустановленные приложения, чтобы уважать выбор пользователя.

В этом туториале вы добавите темный режим в Dark Arts, в приложение с информацией обо всех учителях защиты от темных искусств в Хогвартсе.

В частности, вы узнаете, как:

  • использовать цвета: системный, семантический, динамический, фоновый и фронтальный
  • поддерживать уровни вертикальной проекции рабочими в темной теме
  • использовать различные активы в светлой и темной теме
  • использовать силу символов SF
  • отказаться от темной темы, если захотите
  • и многое другое…

Приступим

Загрузите начальный проект для этого руководства. Дважды щелкните значок DarkArts.xcodeproj, чтобы открыть проект в Xcode.

Познакомьтесь с исходным кодом и файловой структурой проекта.

Запустите. Вы увидите список всех учителей защиты от темных искусств, отсортированных по годам обучения Гарри Поттера и его друзей. Коснитесь любого элемента, чтобы просмотреть дополнительную информацию.

Пользовательский интерфейс приложения блестящий и яркий. Вы измените это по ходу обучения.

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

Когда вы запускаете свое приложение через Xcode, внизу появляется набор кнопок отладки. Нажмите кнопку Environment Overrides, и появится всплывающее окно. В верхней части всплывающего окна есть переключатель Interface Style.

Теперь переключите Interface Style и нажмите кнопку Dark. Приложение будет выглядеть следующим образом:

Не очень темно, да? По крайней мере, фон навигационной панели стал черным. Но список остался белым.

Системные цвета

Самый важный аспект принятия новой темы - это работа с цветами. В iOS 13 Apple пересмотрела цвета и представила несколько новых концепций.

Пока существует UIKit, он предоставляет некоторые предопределенные цвета, такие как .red, .blue и .yellow, к которым вы можете получить статический доступ в UIColor.

Теперь появилась новая палитра красок с префиксом system, в том числе .systemRed и .systemBlue. Эти цвета обеспечивают подходящие и контрастные оттенки как на светлом, так и на темном фоне.

Посмотрите на эту таблицу из руководства Apple Human Interface Guidelines. Как вы можете видеть, каждый системный цвет, также известный как оттенок, имеет различный цветовой код RGB для светлых и темных режимов.

Нажмите на Аластора Муди в приложении. На экране с деталями профиля название дома учителя в Хогвартсе появляется в цвете флага этого дома. Например, Аластор Муди из Хаффлпаффа, поэтому флаг желтый.

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

Откройте TeacherDetailViewController.swift. В viewDidLoad() установите цвет текста houseLabel.

Измените все цвета на соответствующий вариант system:

switch teacher.house {
case .gryffindor:
  houseLabel.textColor = .systemRed
case .hufflepuff:
  houseLabel.textColor = .systemYellow
case .ravenclaw:
  houseLabel.textColor = .systemBlue
case .slytherin:
  houseLabel.textColor = .systemGreen
}

Запустите. Еще раз нажмите на Аластора Муди. Теперь вы видите, что он из Хаффлпаффа.

Семантические цвета

В дополнение к недавно введенным системным цветам iOS 13 также предоставляет семантически определенные цвета. Semantic color передает свое назначение, а не внешний вид или цветовые значения. Таким образом, семантический цвет также автоматически адаптируется к темной теме.

Вам не обязательно знать реальные значения этих цветов. Вместо этого вы используете их на основе их цели использования и получаете доступ к ним, как и к другим цветам через статические вызовы UIColor. Примеры семантических цветов включают в себя .label, .separator, .link, .systemBackground and .systemFill.

Фоновые цвета

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

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

С обоими наборами фоновых цветов вы используете варианты для отображения иерархии следующим образом:

  • Первичный для общего вида.
  • Вторичный для группировки содержимого или элементов в общем представлении.
  • Третичный для группировки содержимого или элементов внутри вторичных элементов.

Чтобы увидеть их в действии, вы добавите фоновые цвета в приложение. На этот раз с помощью Storyboard.

Откройте Main.storyboard. В Dark Arts установите фон как для Table View, так и для TeacherCell в System Background Color.

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

Вы исправите это позже.

Фронтальные цвета

Для содержимого переднего плана, такого как лейблы, можно также использовать различные уровни семантического цвета, чтобы передать важность содержимого. Примеры уровневых цветов включают в себя .label, .secondaryLabel, .tertiaryLabel.

Снова откройте Main.storyboard. Затем, в Dark Arts к Color Name Label примените Label Color.

Запустите, и вы сможете смотреть имена учителей как при темной теме, так и при светлой.

Заметка

Вы можете переключать симулятор между светлой и темной темой не возвращаясь к Xcode. В симуляторе для переключения между ними выберите Features ▸ Toggle Appearance — Shift-Command-A.

Отлично! С помощью нескольких изменений ваше приложение теперь намного лучше поддерживает темную тему.

Но можно еще лучше!

Elevation (вертикальная проекция)

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

Но это не работает в темном режиме. Черная тень не будет видна достаточно, более светлая тень для темного слоя будет выглядеть неестественно.

Для решения этой проблемы Dark Mode использует два набора фоновых цветов: base (базовый) и elevated (приподнятые). Базовые цвета темнее, поэтому фоновые интерфейсы выглядят находящимися в отдалении. elevated цвета светлее, что делает интерфейсы переднего плана объемными.

Вы можете увидеть отличный пример этой концепции в действии в Modal.

Откройте Main.storyboard. В Teacher Detail View Controller установите Background для корневого View в System Background Color. Это точно такое же значение, которое вы установили для фона списка на предыдущих шагах.

Пока вы здесь, измените и следующее:

  • Во-первых, установите Color для Name в Label Color.
  • Во-вторых, установите Color для Taught at Hogwarts на Tertiary Label Color.
  • В-третьих, установите Color для Years at Hogwarts на Secondary Label Color.

Запустите и нажмите на строку, чтобы увидеть экран с деталями профиля.

Посмотрите на фоновые цвета вью контроллера, который находится на задней панели, и экран с деталями профиля, который находится спереди. Хотя вы установили оба из них в один и тот же цвет .systemBackgroundColor, они выглядят по-разному. Это более очевидно в темном режиме.

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

Темный режим динамичен. Это означает, что цвет фона автоматически меняется с базового на elevated (приподнятые), когда интерфейс, как всплывающий или модальный лист, находится на переднем плане.

Динамические цвета

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

Перед тем как перейти в темный режим, вы можете включить пользовательские цвета несколькими способами. Разработчики часто используют код или Asset Catalogs при использовании инициализаторов UIColor. К счастью, Apple обновила оба варианта, чтобы учесть темный режим.

Давайте сначала разберем вариант этого через код.

UITraitCollection

Однако прежде чем продолжить, вам сначала нужно понять концепцию UITraitCollection.

iOS предоставляет интерфейсные среды для любого приложения с помощью свойства traitCollection протокола UITraitEnvironment. UIWindow, UIViewController и UIView - это все классы, соответствующие этому протоколу.

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

Динамический UIColor Provider

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

Откройте TeacherDetailViewController.swift. Замените эту строку кода в viewDidLoad()

headerBackgroundView.backgroundColor = .white

на это:

headerBackgroundView.backgroundColor =
  // 1
  UIColor { traitCollection in
    // 2
    switch traitCollection.userInterfaceStyle {
    case .dark:
      // 3
      return UIColor(white: 0.3, alpha: 1.0)
    default:
      // 4
      return UIColor(white: 0.7, alpha: 1.0)
    }
  }

Разберем этот код:

  1. Вы вызываете новый инициализатор UIColor, который принимает клоужер с одним входом типа UITraitCollection. iOS вызывает этот блок, и в зависимости от стиля пользовательского интерфейса приложения вы получаете определенный цвет. Если пользователь изменяет стиль интерфейса системы, обратный вызов автоматически вызывается снова и, соответственно, меняет цвет.
  2. Вы включаете свойство userInterfaceStyle в traitCollection, чтобы узнать, в каком режиме внешнего вида находится приложение.
  3. Если приложение находится в Dark Mode, оно возвращает более темный оттенок серого.
  4. Если приложение не находится в Dark Mode, оно возвращает более светлый оттенок серого.

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

Создание цветов в коде прекрасно, но если вы не хотите использовать их в Interface Builder. Если вы планируете использовать Interface Builder, вам понадобится Asset Catalog.

Asset Catalog

Вместе с iOS 11, вы получили возможность сохранять свои цвета в Asset Catalog и использовать их как в коде, так и в Interface Builder. Вы можете сделать ваши цвета динамичными с помощью простой настройки.

Откройте Assets.xcassets и посмотрите на папку colors. В Attributes inspector в разделе Appearances можно добавить изменения для цвета. Самым простым вариантом будет Any, Dark, где вы предоставляете новый цвет для темного внешнего вида. Для colors вы найдете динамический цвет с именем thumbnail-border. Он обеспечивает зеленый цвет для темного режима и серый цвет для светлого режима.

Где мы собираемся использовать этот цвет? Вы скоро увидите.

Откройте Main.storyboard. В Dark Arts есть Border View, который создает обводку вокруг аватаров учителей. Сейчас, для его Background установлен статический цвет rw-dark. Поскольку вы не оставляете детали на заднем фоне, измените его на thumbnail-border.

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

Динамические изображения

Возможно, вы заметили красивое фото Хогвартса в нижней части страницы с деталями профиля. Было бы здорово, чтобы Хогвартс был виден и ночью, когда приложение находится в темном режиме?

Вы можете сделать это с dynamic images.

Делаем тоже самое, что и при добавлении вариации к цвету в Asset Catalog для изображений.

Откройте Assets.xcassets. Вы увидите два изображения под названием hogwarts и hogwarts-night. Нажмите кнопку hogwarts.

В Attributes inspector щелкните Appearances и выберите Any, Dark. Появится пустой новый слот.

Щелкните правой кнопкой мыши на hogwarts-night и выберите Show in Finder. Перетащите изображение из Finder в пустой слот, который вы создали в hogwarts. Теперь удалите hogwarts-night, так как у вас есть оба изображения под названием hogwarts.

Запустите и наслаждайтесь прекрасным лунным светом Хогвартса, но держитесь подальше от Люпина.

SFSymbols

Одним из самых крутых дополнений Apple, представленных для iOS 13, был SFSympols - огромный набор последовательных и легко настраиваемых изображений. Эти символы хорошо масштабируются в зависимости от внешнего вида, размера и веса. И самое главное, вы также можете использовать их в своих приложениях бесплатно.

Они также приспособлены к Dark Mode. Вы можете покрасить их в любой динамичный цвет, и они прекрасно адаптируются. Если ваше приложение не нуждается в конкретных изображениях и ассетах, SFSymbols может быть отличным выбором для вас.

Пришло время добавить немного деталей на экран, добавив значок дома рядом с названием дома с помощью SFSymbols.

Откройте TeacherDetailViewController.swift. В последней строке viewDidLoad() добавьте:

houseImageView.image = UIImage(systemName: "house.fill")

Эта строка кода использует новый инициализатор для UIImage, который принимает имя символа в каталоге SFSymbols.

Соберите проект. Посмотрите на красивую иконку дома. Не так шикарно, как комнаты в Хогвартсе, но тем не менее.

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

Над строкой, которую вы только что вставили, есть фрагмент кода, который устанавливает tintColor в houseImageView.

Замените следующее

houseImageView.tintColor = .black

этим:

houseImageView.tintColor = houseLabel.textColor

Эта строка устанавливает tintColor при houseImageView в textColor при houseLabel. Помните, что вы использовали системные цвета для этой метки, чтобы она динамически адаптировалась к внешнему виду устройства.

Запустите проект. Цвет значка дома теперь переключается при переключении режимов внешнего вида.

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

Заметка

Apple предоставила сопутствующее Mac-приложение для SFSymbols. Вы можете скачать его здесь и просмотреть весь каталог. Имя строки, которое вы использовали в инициализаторе UIColor, взято из этого приложения.

Выход из темной темы

Темная тема популярна так, как никогда прежде. Вы можете установить темную тему для всей системы, и все приложения Apple и многие сторонние приложения включают его. Если вы откажитесь от темного режима, то это может вызвать напряжение глаз у пользователей, которые предпочитают его.

Однако, если вы уверены, что хотите отказаться от темного режима, у вас есть несколько вариантов:

  1. Выключите темный режим для всего приложения с помощью клавиши UIUserInterfaceStyle в разделе Info.plist.
  2. Установите стиль интерфейса в UIWindow, что обычно охватывает всё приложение.
  3. Задайте стиль интерфейса для конкретного UIView или UIViewController.

Вы будете устанавливать их в приложение по очереди.

Заметка

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

Отказ от темной темы с помощью Info.plist

Откройте Info.plist. Затем добавьте ключ с именем UIUserInterfaceStyle и переключите на Light.

Запустите приложение. Все сияет, будто вы ничего и не делали.

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

Отказ от темной темы с помощью UIWindow

Откройте SceneDelegate.swift. Замените это

var window: UIWindow?

этим:

var window: UIWindow? {
  didSet {
    window?.overrideUserInterfaceStyle = .light
  }
}

Поскольку это приложение использует сториборды, система устанавливает window.

Этот блок кода устанавливает наблюдатель свойств Swift на window. Как только это свойство установлено, вы переопределяете стиль интерфейса на .light. Поскольку это приложение использует только одно окно (window), переопределение стиля в окне приводит к тому, что приложение ведет себя так, как если бы вы установили этот ключ в Info.plist.

Запустите, чтобы проверить:

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

Отказ от темной темы с помощью UIViewController

Откройте TeacherDetailViewController.swift. Вы сделаете этот контроллер вида мятежником, который не уважает темный режим.

В viewDidLoad(), сразу после вызова super.viewDidLoad(), вставьте:

overrideUserInterfaceStyle = .light

Эта строка переопределяет стиль для данного конкретного контроллера вида.

Запустите. Проверьте работоспособность темной темы! Страница списка темная, а страница сведений светлая.

Оригинал статьи

Комментарии

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: