How to get RGB components from Color in SwiftUI
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:
iOS / macOS
import SwiftUI#if canImport(UIKit)import UIKit#elseif canImport(AppKit)import AppKit#endifextension 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) }}
Usage
Color.red.components.red // 0.9999999403953552 // <- SwiftUI Colors are not pure!
Waiting for an API I've abused CustomStringConvertible
protocol for the simple rgba case where the color description format is #rrggbbaa
debugPrint(Color.red)debugPrint(Color(red: 1.0, green: 0.0, blue: 0.0))debugPrint(Color(red: 1.0, green: 0.3, blue: 0.0))debugPrint(Color(.sRGB, red: 1.0, green: 0.0, blue: 0.5, opacity: 0.3))debugPrint(Color(hue: 1.0, saturation: 0.0, brightness: 1.0))debugPrint(Color(.displayP3, red: 1.0, green: 0.0, blue: 0.0, opacity: 1.0).description)red#FF0000FF#FF4C00FF#FF00804D#FFFFFFFF"DisplayP3(red: 1.0, green: 0.0, blue: 0.0, opacity: 1.0)"
as you can see, things like Color.red just dump "red" but if you are working with simple RGB colors generated by code (ie from a color picker) then this is not too bad
extension SwiftUI.Color { var redComponent: Double? { let val = description guard val.hasPrefix("#") else { return nil } let r1 = val.index(val.startIndex, offsetBy: 1) let r2 = val.index(val.startIndex, offsetBy: 2) return Double(Int(val[r1...r2], radix: 16)!) / 255.0 } var greenComponent: Double? { let val = description guard val.hasPrefix("#") else { return nil } let g1 = val.index(val.startIndex, offsetBy: 3) let g2 = val.index(val.startIndex, offsetBy: 4) return Double(Int(val[g1...g2], radix: 16)!) / 255.0 } var blueComponent: Double? { let val = description guard val.hasPrefix("#") else { return nil } let b1 = val.index(val.startIndex, offsetBy: 5) let b2 = val.index(val.startIndex, offsetBy: 6) return Double(Int(val[b1...b2], radix: 16)!) / 255.0 } var opacityComponent: Double? { let val = description guard val.hasPrefix("#") else { return nil } let b1 = val.index(val.startIndex, offsetBy: 7) let b2 = val.index(val.startIndex, offsetBy: 8) return Double(Int(val[b1...b2], radix: 16)!) / 255.0 }}
You can use UIColor and transform the UIColor to Color after.Code:
extension UIColor { func hexValue() -> String { let values = self.cgColor.components var outputR: Int = 0 var outputG: Int = 0 var outputB: Int = 0 var outputA: Int = 1 switch values!.count { case 1: outputR = Int(values![0] * 255) outputG = Int(values![0] * 255) outputB = Int(values![0] * 255) outputA = 1 case 2: outputR = Int(values![0] * 255) outputG = Int(values![0] * 255) outputB = Int(values![0] * 255) outputA = Int(values![1] * 255) case 3: outputR = Int(values![0] * 255) outputG = Int(values![1] * 255) outputB = Int(values![2] * 255) outputA = 1 case 4: outputR = Int(values![0] * 255) outputG = Int(values![1] * 255) outputB = Int(values![2] * 255) outputA = Int(values![3] * 255) default: break } return "#" + String(format:"%02X", outputR) + String(format:"%02X", outputG) + String(format:"%02X", outputB) + String(format:"%02X", outputA) }}