如果我有一个SwiftUI Color:
Color
let col: Color = Color(red: 0.5, green: 0.5, blue: 0.5)
如何从col中获取RGB分量?就像这样:
col
print(col.components.red)
在UIKit中,我可以使用UIColor.getRed,但在SwiftUI中似乎没有等效的。
UIColor.getRed
yc0p9oo01#
您可以要求在给定的环境中解析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) } } }
上面的代码是使用Xcode 15 beta 1为iOS 17 beta 1编写的
现在有一个新的初始化器,它接受Color并返回UIColor(对于iOS)或NSColor(对于macOS)。在这些工具的帮助下,您可以实现以下扩展:
UIColor
NSColor
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) ) } }
Color.red.components.red // 0.9999999403953552 // <- SwiftUI Colors are not pure!
fhg3lkii2#
简单的一行程序:
print(UIColor(Color.blue).cgColor.components)
你会得到一个[CGFloat]? [red,绿色,blue,alpha]。
[CGFloat]?
xa9qqrwz3#
我在简单的rgba情况下滥用了CustomStringConvertible协议,其中颜色描述格式为#rrggbbaa
CustomStringConvertible
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)"
正如你所看到的,像www.example.com这样的东西Color.red只是转储“红色”,但如果你正在使用由代码生成的简单RGB颜色(即从颜色选择器),那么这还不算太糟糕
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 } }
jm2pwxwz4#
我发现@Mojtaba Hosseinis的答案工作正常,除非你在资产中声明了颜色,颜色有亮有暗。然后我发现在使用UIColor(self)时,黑暗的外观不知何故丢失了。以下是我提出的一个解决方案:注意,这只适用于iOS,因为我的应用程序只适用于iOS,当然你也可以像@Mojtaba Hosseini一样做,并将其调整为macOS。
UIColor(self)
iOS
macOS
extension Color { var components: (r: Double, g: Double, b: Double, o: Double)? { let uiColor: UIColor var r: CGFloat = 0 var g: CGFloat = 0 var b: CGFloat = 0 var o: CGFloat = 0 if self.description.contains("NamedColor") { let lowerBound = self.description.range(of: "name: \"")!.upperBound let upperBound = self.description.range(of: "\", bundle")!.lowerBound let assetsName = String(self.description[lowerBound..<upperBound]) uiColor = UIColor(named: assetsName)! } else { uiColor = UIColor(self) } guard uiColor.getRed(&r, green: &g, blue: &b, alpha: &o) else { return nil } return (Double(r), Double(g), Double(b), Double(o)) } }
这个想法是使用UIColor(named:)初始化器,其中所有外观都是正确的。幸运的是,我们在assets中设置的名称保存在Color的描述中。我们只需要抽象它,因为还有其他信息,即bundle等。
UIColor(named:)
oipij1gg5#
基于@Mojtaba的回答,我想出了一个更短,更灵活的版本:
#if canImport(UIKit) import UIKit #elseif canImport(AppKit) import AppKit #endif extension Color { #if canImport(UIKit) var asNative: UIColor { UIColor(self) } #elseif canImport(AppKit) var asNative: NSColor { NSColor(self) } #endif var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { let color = asNative.usingColorSpace(.deviceRGB)! var t = (CGFloat(), CGFloat(), CGFloat(), CGFloat()) color.getRed(&t.0, green: &t.1, blue: &t.2, alpha: &t.3) return t } var hsva: (hue: CGFloat, saturation: CGFloat, value: CGFloat, alpha: CGFloat) { let color = asNative.usingColorSpace(.deviceRGB)! var t = (CGFloat(), CGFloat(), CGFloat(), CGFloat()) color.getHue(&t.0, saturation: &t.1, brightness: &t.2, alpha: &t.3) return t } }
做asNative.redComponent等也可能有用顺便说一句
3zwtqj6y6#
答案是no-目前还没有API这样做,但是...大多数SwiftUI结构都有private字段,就像Color一样。您可以使用Mirror来提取此类信息-但请记住,它效率不高。以下是如何提取SwiftUI Color的十六进制表示-用于教育目的。复制并粘贴到Xcode 11Playground。
private
Mirror
import UIKit import SwiftUI let systemColor = Color.red let color = Color(red: 0.3, green: 0.5, blue: 1) extension Color { var hexRepresentation: String? { let children = Mirror(reflecting: color).children let _provider = children.filter { $0.label == "provider" }.first guard let provider = _provider?.value else { return nil } let providerChildren = Mirror(reflecting: provider).children let _base = providerChildren.filter { $0.label == "base" }.first guard let base = _base?.value else { return nil } var baseValue: String = "" dump(base, to: &baseValue) guard let firstLine = baseValue.split(separator: "\n").first, let hexString = firstLine.split(separator: " ")[1] as Substring? else { return nil } return hexString.trimmingCharacters(in: .newlines) } } systemColor.hexRepresentation color.hexRepresentation
像.red,.white等颜色,似乎没有太多的信息,当dumped。只是他们的“系统”名称。
.red
.white
dumped
▿ red ▿ provider: SwiftUI.(unknown context at $1297483bc).ColorBox<SwiftUI.SystemColorType> #0 - super: SwiftUI.(unknown context at $129748300).AnyColorBox - base: SwiftUI.SystemColorType.red
使用red/blue/green组件示例化的Color则会这样做。
red
blue
green
▿ #4C80FFFF ▿ provider: SwiftUI.(unknown context at $11cd2e3bc).ColorBox<SwiftUI.Color._Resolved> #0 - super: SwiftUI.(unknown context at $11cd2e300).AnyColorBox ▿ base: #4C80FFFF - linearRed: 0.073238954 - linearGreen: 0.21404114 - linearBlue: 1.0 - opacity: 1.0
在Playground,你会看到:
systemColor.hexRepresentation
nil
color.hexRepresentation
"#4C80FFFF"
ccgok5k57#
您可以使用UIColor并将UIColor转换为Color after。代码:
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) } }
7条答案
按热度按时间yc0p9oo01#
iOS 17/ macOS 14(高级但原生)
您可以要求在给定的环境中解析
Color
组件***,因为不同的环境中颜色是不同的(例如在黑暗和明亮的环境中)。在下面的示例中,我使用所用颜色的当前环境来解决它。上面的代码是使用Xcode 15 beta 1为iOS 17 beta 1编写的
iOS 14 / macOS 10.16
现在有一个新的初始化器,它接受
Color
并返回UIColor
(对于iOS)或NSColor
(对于macOS)。在这些工具的帮助下,您可以实现以下扩展:用法
fhg3lkii2#
简单的一行程序:
你会得到一个
[CGFloat]?
[red,绿色,blue,alpha]。xa9qqrwz3#
我在简单的rgba情况下滥用了
CustomStringConvertible
协议,其中颜色描述格式为#rrggbbaa正如你所看到的,像www.example.com这样的东西Color.red只是转储“红色”,但如果你正在使用由代码生成的简单RGB颜色(即从颜色选择器),那么这还不算太糟糕
jm2pwxwz4#
我发现@Mojtaba Hosseinis的答案工作正常,除非你在资产中声明了颜色,颜色有亮有暗。
然后我发现在使用
UIColor(self)
时,黑暗的外观不知何故丢失了。以下是我提出的一个解决方案:注意,这只适用于
iOS
,因为我的应用程序只适用于iOS
,当然你也可以像@Mojtaba Hosseini一样做,并将其调整为macOS
。这个想法是使用
UIColor(named:)
初始化器,其中所有外观都是正确的。幸运的是,我们在assets中设置的名称保存在Color
的描述中。我们只需要抽象它,因为还有其他信息,即bundle等。oipij1gg5#
基于@Mojtaba的回答,我想出了一个更短,更灵活的版本:
做asNative.redComponent等也可能有用顺便说一句
3zwtqj6y6#
答案是no-目前还没有API这样做,但是...
大多数SwiftUI结构都有
private
字段,就像Color
一样。您可以使用
Mirror
来提取此类信息-但请记住,它效率不高。以下是如何提取SwiftUI
Color
的十六进制表示-用于教育目的。复制并粘贴到Xcode 11Playground。
像
.red
,.white
等颜色,似乎没有太多的信息,当dumped
。只是他们的“系统”名称。
使用
red
/blue
/green
组件示例化的Color
则会这样做。在Playground,你会看到:
systemColor.hexRepresentation
返回nil
color.hexRepresentation
返回"#4C80FFFF"
ccgok5k57#
您可以使用UIColor并将UIColor转换为Color after。代码: