paint-brush
ColorScheme Related Color Without Assetsby@adobysh

ColorScheme Related Color Without Assets

by Andrei DobyshJuly 13th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Storing colors with light and dark appearances in code instead of assets. Example of storing: extension Color { static let primaryColor = Color(🟩, dark: 🟥) } Example of usage: let color = Color.primaryColor Result: color will be displayed according to the current color theme.
featured image - ColorScheme Related Color Without Assets
Andrei Dobysh HackerNoon profile picture

I like to use colors as variables/constants like Color(.primaryColor) instead of text names like Color("primary_color"). It's faster, there's less chance of making a mistake, and you can quickly refactor by renaming the color name globally throughout the code.


Going through possible solutions to make it easier to work with colors, I decided that I dоn't want to use Swift R for this purpose for a number of reasons. I also don't plan to use Storyboard or Xib files. So, I decided to store colors in code.


But I ran into a problem; I couldn't find a standard easy way to create a dynamic color using code that will change automatically depending on the current color scheme in real-time.


Later, I found a mechanism in UIColor that allows me to do the intended thing, and I made an initializer based on it.


An initializer accepting colors as UIColor would be handy for concise writing with color literals:

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
      }
    })
  }
}


Example of use with color literals:

extension Color {
  // Instead of a 🟩 & 🟥 use something like this:
  // #colorLiteral(red: 0, green: 1, blue: 0, alpha: 1).
  // Commenting code with ``//`` 
  // will switch between ``🟩`` & ``#colorLiteral(...)``.
  static let primaryColor = Color(🟩, dark: 🟥)
}


An initializer accepting colors as SwiftUI.Color will probably come in handy too:

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)
  }
}


Example of use with constants:

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


Whole demo app:

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)
    }
  }
}


Result:


I will be glad to answer your comments if you have any remarks or ideas about it.


Thank you for your attention. ❤️🤖