ITNEWS.pro
…
26 декабря 2023 в 19:08
Подписаться
Динамичные цвета в iOS без использования ассетов

Мне нравится использовать цвета как константы, например Color(.primaryColor), а не текстовые имена, например Color("primary_color"). Это быстрее, меньше шансов ошибиться, и можно быстро провести рефакторинг, глобально переименовав название цвета во всем коде.


Перебирая возможные решения для упрощения работы с цветами, я решил, что не хочу использовать Swift R для этих целей по ряду причин. Я также не планирую использовать Storyboard или Xib-файлы. Поэтому я решил хранить цвета в коде.


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


Позже я нашел механизм в UIColor, который позволяет мне сделать задуманное, и сделал инициализатор на его основе.


Инициализатор, принимающий цвета как UIColor, будет удобен для лаконичной записи с литералами цветов:

extension Color {
  init(_ unspecifiedColor: UIColor,
       dark darkColor: UIColor,
       light lightColor: UIColor? = nil) {
    self = Color(UIColor {
      switch $0.userInterfaceStyle {
      case .unspecified:
        return unspecifiedColor
      case .dark:
        return darkColor
      case .light:
        return lightColor ?? unspecifiedColor
      @unknown default:
        return unspecifiedColor
      }
    })
  }
}


Пример использования с литералами цвета:

extension Color {
  // Вместо 🟩 & 🟥 используйте что-то вроде этого:
  // #colorLiteral(red: 0, green: 1, blue: 0, alpha: 1).
  // Комментирование кода с помощью ``//``
  // будет переключаться между ``🟩`` и ``#colorLiteral(...)``.
  static let primaryColor = Color(🟩, dark: 🟥)
}


Инициализатор, принимающий цвета как SwiftUI.Color, тоже пригодится:

extension Color {
  init(_ unspecifiedColor: Color,
       dark darkColor: Color,
       light lightColor: Color? = nil) {
    let lightUIColor = lightColor.map { UIColor($0) }
    self.init(UIColor(unspecifiedColor),
              dark: UIColor(darkColor),
              light: lightUIColor)
  }
}


Пример использования с константами:

extension Color {
  static let primaryColor = Color(.red, dark: .blue)
}


Демо-приложение:

extension Color {
  static let primaryColor = Color(🟩, dark: 🟥)
}

@main
struct DynamicColorApp: App {
  @State var colorSheme: ColorScheme = .light
  
  var body: some Scene {
    WindowGroup {
      VStack {
        Text("Green by day and red by night")
          .foregroundColor(.primaryColor)
        Button("light") {
          colorSheme = .light
        }
        Button("dark") {
          colorSheme = .dark
        }
      }
      .preferredColorScheme(colorSheme)
    }
  }
}


Результат:


Буду рад ответить на комментарии, если есть какие-либо замечания или идеи по этому решению.


Спасибо за внимание ❤️🤖

Подписывайся на наш Telegram и не пропусти главные новости!