UIColor дает возможность настроить цвет для Dark Mode, дает семантический набор цветов "от Apple", а также дает возможность задать не только цвет, но и паттерн заполнения пространства, что как бы кричит нам, что UIColor это вовсе не цвет. Давайте слегка заглянем в эти чертоги UIColor.

UIColor это класс который хранит данные о цвете и прозрачности. Цвет в iOS может быть представлен в разных цветовых пространствах, самое известное из которых RGB. На самом деле, сам цвет хранится в свойстве cgColor класса CGColor. В iOS существуют несколько сущностей, которые могут хранить информацию о цвете - каждый для своего фреймворка:

  • для UIKit это класс UIColor, 

  • для SwiftUI это структура Color, 

  • для Core Graphics это класс CGColor, 

  • для Core Image это класс CIColor

В данной статье я постараюсь рассказать о классе UIColor, который является частью фреймворка UIKit.

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

В UIKit есть некоторые предопределенные цвета, которые вы можете использовать в своем проекте. Например, зелёный UIColor.green или часто достаточно написать просто .green. Написав так, будет использован конкретный цвет со значениями RGB  0.0, 1.0, 0.0 и уровнем прозрачности 1.0. Но в UIColor, определен также цвет UIColor.systemGreen. Чем он отличается от обычного UIColor.green? 

Начиная с iOS 13.0 появился Dark Mode. Пользователь может выбрать в настройках системы в каком цветовом теме ему комфортнее работать - в светлой теме или в тёмной. И зеленый цвет для этих режимов будет немного отличаться. Более того, пользователь для комфортного восприятия может выбрать высококонтрастный режим, повышающий контрастность между элементами интерфейса и фона. И зеленый цвет для этого режима тоже будет другим. 

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

  • systemBlue

  • systemIndigo

  • systemOrange

  • systemPink

  • systemPurple

  • systemRed

  • systemTeal

  • systemYellow

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

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

  • systemGray

  • systemGray2

  • systemGray3

  • systemGray4

  • systemGray5

  • systemGray6

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

Как вы могли заметить среди этих цветов нет цветов Black или White, которые в основном как раз используются для текста или фона. Тут как раз приходят на помощь семантические цвета.

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

Концепция семантических цветов позволяет абстрагироваться от конкретных цветов, сделав акцент на предназначении цвета. В UIKit нам знаком такой цвет как tintColor, который обозначает цвет, который призывает пользователя к действию - например, это может быть цвет системных кнопок, ссылок, вкладок в UISegmentControl и т.п. В вашем приложении может быть определен брендированный цвет - например, мы можем назвать его как brandColor или primaryBrandColor/secondaryBrandColor. Или это может быть свой уникальный цвет всех текстовых элементов.

Смысл использования семантических цветов в том, чтобы определить их в одном месте и дальше ссылаться из всех частей приложения только на одно место - место где вы определили семантические цвета. К примеру, вы хотите использовать красный цвет для всех UILabel в вашем приложении. Вместо того, чтобы в каждом UILabel задать тексту цвет .red, гораздо удобнее определить свой семантический цвет:

let primaryTextColor = UIColor.red

и во всех UILabel его использовать:

label.textColor = primaryTextColor

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

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

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

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

Цвета текста:

  • label - для обозначения основного текста

  • secondaryLabel - вторичный текст

  • tertiaryLabel - текст третьей значимости

  • quaternaryLabel - текст четвертой значимости

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

Цвета для заполнения:

  • systemFill

  • secondarySystemFill

  • tertiarySystemFill

  • quaternarySystemFill

Apple предлагает использовать эти цвета для наполнения разных фигур/контролов типа слайдеров, полей поиска, кнопок и т.п.

Цвет для плейсхолдера:

  • placeholderText

Цвета для фона:

  • systemBackground

  • secondarySystemBackground

  • tertiarySystemBackground

Использовать для разного вида фонов.

Цвета для фонов сгруппированных элементов:

  • systemGroupedBackground

  • secondarySystemGroupedBackground

  • tertiarySystemGroupedBackground

Используются для таблиц со стилем .grouped для фона сгруппированных элементов.

Цвета для разделителей:

  • separator

  • opaqueSeparator

Цвет для ссылок:

  • link

Отдельно цвета для текста, которые не адаптируются под темную или светлую тему:

  • darkText

  • lightText

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

Подробнее про эти цвета можно почитать на сайте Apple.

Как создать цвет, который будет адаптироваться под Dark или Light режимы

Первый вариант - в XCode в Assets проекта добавить для каждого цвета Color Set, в котором можно отдельно задать цвета для Dark и Light Mode в настройке Appearances. Там же можно задать, что вы хотите для данного цвета задать параметры для высококонтрастного режима.

Где можно найти настроки цвета в Assets в XCode
Где можно найти настроки цвета в Assets в XCode

В дальнейшем к этому цвету можно обращаться так:

let color = UIColor(named: "ColorName")

этот цвет автоматически будет меняться "на лету" при изменении режима настройки в iOS.

Второй вариант - задать условия и значения цвета в коде, в зависимости от текущих параметров системы.

Делается это в конструкторе UIColor:

init(dynamicProvider: @escaping (UITraitCollection) -> UIColor)

UITraitCollection содержит в себе основные параметры относящиеся к экрану - вертикальный или горизонтальный режим, Dark или Light режим, контрастность и т.п. Нас прежде всего интересует userInterfaceStyle которое говорит о текущем режиме.

Пример:

let color = UIColor { traitCollection -> UIColor in

    switch traitCollection.userInterfaceStyle {

        case .light, .unspecified: return .white

        case .dark: return .black

    }

}

Какие еще есть возможности для создания цвета

Конструкторы для создания UIColor можно разделить на три типа:

  • для создания в разных пространствах цветов HSB, RGB

  • для создания UIColor на основе цветов из других нативных фреймворков

  • для создания на основе паттерна картинки

    интересный вариант - создать UIColor на основе картинки ...

init(patternImage image: UIImage)

Данный конструктор создает UIColor, при этом мы не задаем цвет, а передаем в качестве основы картинку. В итоге назначив этот цвет, например, тексту UILabel, вы получете интересный эффект - текст будет отображен при помощи паттерна картинки (см. обложку статьи).

Это что же получается - цвет это может быть вовсе не цвет, а паттерн. Получается что цвет в данном случае это скорее "как нам наполнить пространство", чем "каким цветом тут покрасить".

Вывод

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