Search code examples
swiftcolorsrgbswiftui

How to get RGB components from Color in SwiftUI


If I have a SwiftUI Color:

let col: Color = Color(red: 0.5, green: 0.5, blue: 0.5)

How do I get the RGB components from col?
Like this maybe:

print(col.components.red)

In UIKit, I could use UIColor.getRed but there doesn't seem to be an equivalent in SwiftUI.


Solution

  • iOS 17/ macOS 14 (advanced but native)

    You can ask for resolving Color components in the given environment, because colors are different in different environments (for example in dark and light environments). In the following sample, I resolved it using the current environment of the used color.

    struct ContentView: View {
        @Environment(\.self) var environment
        @State private var color = Color.red
        @State private var components: Color.Resolved?
    
        var body: some View {
            VStack {
                ColorPicker("Select your favorite color", selection: $color)
    
                if let components {
                    Text("R: \(components.red)")
                    Text("G: \(components.green)")
                    Text("B: \(components.blue)")
                    Text("A: \(components.opacity)")
                    Text("HEX: \(components.description)")
                }
            }
            .padding()
            .onChange(of: color, initial: true) { components = color.resolve(in: environment) }
        }
    }
    

    The code above has been written for iOS 17 beta 1 using Xcode 15 beta 1


    iOS 14 / macOS 10.16

    There is a new initializer that takes a Color and returns a UIColor for iOS or NSColor for macOS now. With the help of those you can implement the following extensions:

    import SwiftUI
    
    #if canImport(UIKit)
    import UIKit
    #elseif canImport(AppKit)
    import AppKit
    #endif
    
    extension Color {
        var components: (red: CGFloat, green: CGFloat, blue: CGFloat, opacity: CGFloat) {
    
            #if canImport(UIKit)
            typealias NativeColor = UIColor
            #elseif canImport(AppKit)
            typealias NativeColor = NSColor
            #endif
    
            var r: CGFloat = 0
            var g: CGFloat = 0
            var b: CGFloat = 0
            var o: CGFloat = 0
    
            guard NativeColor(self).getRed(&r, green: &g, blue: &b, alpha: &o) else {
                // You can handle the failure here as you want
                return (0, 0, 0, 0)
            }
    
            return (r, g, b, o)
        }
    
        var hex: String {
            String(
                format: "#%02x%02x%02x%02x",
                Int(components.red * 255),
                Int(components.green * 255),
                Int(components.blue * 255),
                Int(components.opacity * 255)
            )
        }
    }
    

    Usage

    Color.red.components.red // 0.9999999403953552 // <- SwiftUI Colors are not pure!