Почему #FF5733 — это не просто случайный набор символов?
Вы когда-нибудь задумывались, что скрывается за привычной записью #FF5733 в вашем коде? Для большинства разработчиков это просто «какой-то оранжево-розовый цвет». Но если копнуть глубже, за этим шестизначным кодом стоит элегантная математика, битовые операции и история, уходящая корнями в старые мониторы и спецификации HTML.
В этой статье мы разберём hex-цвета в Swift с нуля. Вы узнаете, как работают RGB-каналы, почему hex-формат так популярен, и — самое главное — как написать свой собственный UIColor (или Color для SwiftUI), который принимает шестнадцатеричные строки. И да, мы рассмотрим реальный код, который вы сможете использовать прямо сегодня.
Если вы когда-нибудь искали ответ на вопрос «How to use hex color values in Swift» на Stack Overflow — вы попали по адресу. Только теперь с русским переводом и глубоким объяснением.
Анатомия hex-цвета: откуда берутся эти цифры?
Давайте начнём с самого простого. Цвет на экране — это комбинация трёх базовых компонентов: Red (красный), Green (зелёный) и Blue (синий). Каждый из них может принимать значение от 0 до 255. Почему 255? Потому что это максимальное число, которое можно записать в один байт (8 бит).
Hex-формат — это просто компактный способ записи этих трёх чисел.
#FF5733разбивается на три пары:FF,57,33.FFв десятичной системе = 255 (максимум красного).57= 87 (зелёный).33= 51 (синий).- Итоговый цвет: RGB(255, 87, 51) — яркий коралловый.
Шестнадцатеричная система (основание 16) использует цифры от 0 до 9 и буквы от A до F. Это позволяет записать число от 0 до 255 всего двумя символами. Удобно, правда?
Почему hex так популярен в вебе и iOS?
Исторически hex-коды пришли из веб-дизайна. Когда CSS только начинал развиваться, #RRGGBB стал стандартом для указания цветов. Swift и UIKit переняли эту традицию, но с одним нюансом: встроенного парсера hex-строк в UIColor нет.
Каждый iOS-разработчик хотя бы раз писал extension для UIColor, который превращает "#FF5733" в UIColor. Это стало своеобразным «ритуалом посвящения». И сегодня мы пройдём этот ритуал вместе.
Пишем свой hex-парсер в Swift (пошагово)
Давайте создадим удобный и безопасный инициализатор для UIColor, который принимает hex-строку. Мы разберём каждый шаг.
Шаг 1: Базовая структура
import UIKit
extension UIColor {
convenience init?(hex: String) {
// Здесь будет магия
}
}
Мы используем convenience init? (проваливающийся), потому что строка может быть невалидной.
Шаг 2: Очищаем строку
Пользователи могут передать "#FF5733", "FF5733" или даже "0xFF5733". Нам нужно убрать всё лишнее.
var hexString = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if hexString.hasPrefix("#") {
hexString.removeFirst()
}
if hexString.hasPrefix("0X") {
hexString.removeFirst(2)
}
Шаг 3: Проверяем длину
Стандартный hex-код — это 6 символов (RRGGBB). Но есть и 8-символьный формат (RRGGBBAA), где AA — альфа-канал (прозрачность). Мы поддержим оба.
guard hexString.count == 6 || hexString.count == 8 else {
return nil
}
Шаг 4: Парсим строку в числа
Теперь самое интересное. Нам нужно превратить строку в шестнадцатеричное число, а затем извлечь из него компоненты RGB.
guard let hexValue = UInt64(hexString, radix: 16) else {
return nil
}
let red, green, blue, alpha: CGFloat
if hexString.count == 6 {
// Формат RRGGBB — альфа = 1.0
red = CGFloat((hexValue >> 16) & 0xFF) / 255.0
green = CGFloat((hexValue >> 8) & 0xFF) / 255.0
blue = CGFloat(hexValue & 0xFF) / 255.0
alpha = 1.0
} else {
// Формат RRGGBBAA
red = CGFloat((hexValue >> 24) & 0xFF) / 255.0
green = CGFloat((hexValue >> 16) & 0xFF) / 255.0
blue = CGFloat((hexValue >> 8) & 0xFF) / 255.0
alpha = CGFloat(hexValue & 0xFF) / 255.0
}
self.init(red: red, green: green, blue: blue, alpha: alpha)
Разбираем битовые операции: что здесь происходит?
Если вы не знакомы с побитовыми операциями, этот код может выглядеть как магия. Давайте разложим всё по полочкам.
Представьте, что hexValue — это число 0xFF5733. В двоичном виде это 24 бита:
- Биты 23-16: красный канал (
0xFF) - Биты 15-8: зелёный канал (
0x57) - Биты 7-0: синий канал (
0x33)
Операция >> 16 (сдвиг вправо на 16 бит) «сдвигает» красный канал в младшие биты. Теперь число стало 0xFF.
Операция & 0xFF (побитовое И) отсекает всё, кроме последних 8 бит. Если бы мы не сделали этого, при сдвиге на 8 бит могли бы остаться «хвосты» от красного канала.
Результат: мы получаем чистые значения от 0 до 255 для каждого канала. После деления на 255.0 получаем числа от 0.0 до 1.0 — именно то, что ожидает UIColor.
Полный код для копирования
Вот готовый extension, который можно добавить в любой проект:
import UIKit
extension UIColor {
/// Создаёт UIColor из hex-строки.
/// Под