Gav*_*sen 5 colors uicolor ios swiftui
尝试将SwiftUI颜色更改为UIColor的实例。
我可以轻松地从UIColor中获取RGBA,但是我不知道如何获取“ Color”实例以返回相应的RGB和不透明度值。
@EnvironmentObject var colorStore: ColorStore
init() {
let red = //get red value from colorStore.primaryThemeColor
let green = //get red value from colorStore.primaryThemeColor
let blue = //get red value from colorStore.primaryThemeColor
let opacity = //get red value from colorStore.primaryThemeColor
let color = UIColor(red: red, green: green, blue: blue, alpha: opacity)
UINavigationBar.appearance().tintColor = color
}
Run Code Online (Sandbox Code Playgroud)
...或者也许有更好的方法来完成我想要的。
Moj*_*ini 40
有一个新的初始化,需要一个Color和返回UIColor的的iOS或NSColor用于MacOS的现在。所以:
UIColor(Color.red)
Run Code Online (Sandbox Code Playgroud)
NSColor(Color.red)
Run Code Online (Sandbox Code Playgroud)
UIColor(Color.red).cgColor /* For iOS */
NSColor(Color.red).cgColor /* For macOS */
Run Code Online (Sandbox Code Playgroud)
如果您正在寻找颜色组件,您可以在此答案中找到有用的扩展
另外,请查看如何将 UIColor 转换为 SwiftUI 的颜色
tur*_*ted 29
这个解决方案怎么样?
extension Color {
func uiColor() -> UIColor {
if #available(iOS 14.0, *) {
return UIColor(self)
}
let components = self.components()
return UIColor(red: components.r, green: components.g, blue: components.b, alpha: components.a)
}
private func components() -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) {
let scanner = Scanner(string: self.description.trimmingCharacters(in: CharacterSet.alphanumerics.inverted))
var hexNumber: UInt64 = 0
var r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0, a: CGFloat = 0.0
let result = scanner.scanHexInt64(&hexNumber)
if result {
r = CGFloat((hexNumber & 0xff000000) >> 24) / 255
g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
a = CGFloat(hexNumber & 0x000000ff) / 255
}
return (r, g, b, a)
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
let uiColor = myColor.uiColor()
Run Code Online (Sandbox Code Playgroud)
这有点黑客,但至少在我们获得有效方法之前它是一些东西。这里的关键是self.description它给出了颜色的十六进制描述(如果它不是动态的,我应该添加)。剩下的只是计算来获取颜色分量,并创建一个UIColor.
目前,这不能直接在 SwiftUI API 中提供。但是,我设法使用了调试打印和dump. 我发现所有其他解决方案都无法解释Color从名称、包、.displayP3颜色空间、a UIColor、静态系统Color或不透明度改变的任何颜色进行的初始化。我的解决方案解决了上述所有问题。
fileprivate struct ColorConversionError: Swift.Error {
let reason: String
}
extension Color {
@available(*, deprecated, message: "This is fragile and likely to break at some point. Hopefully it won't be required for long.")
var uiColor: UIColor {
do {
return try convertToUIColor()
} catch let error {
assertionFailure((error as! ColorConversionError).reason)
return .black
}
}
}
fileprivate extension Color {
var stringRepresentation: String { description.trimmingCharacters(in: .whitespacesAndNewlines) }
var internalType: String { "\(type(of: Mirror(reflecting: self).children.first!.value))".replacingOccurrences(of: "ColorBox<(.+)>", with: "$1", options: .regularExpression) }
func convertToUIColor() throws -> UIColor {
if let color = try OpacityColor(color: self) {
return try UIColor.from(swiftUIDescription: color.stringRepresentation, internalType: color.internalType).multiplyingAlphaComponent(by: color.opacityModifier)
}
return try UIColor.from(swiftUIDescription: stringRepresentation, internalType: internalType)
}
}
fileprivate struct OpacityColor {
let stringRepresentation: String
let internalType: String
let opacityModifier: CGFloat
init(stringRepresentation: String, internalType: String, opacityModifier: CGFloat) {
self.stringRepresentation = stringRepresentation
self.internalType = internalType
self.opacityModifier = opacityModifier
}
init?(color: Color) throws {
guard color.internalType == "OpacityColor" else {
return nil
}
let string = color.stringRepresentation
let opacityRegex = try! NSRegularExpression(pattern: #"(\d+% )"#)
let opacityLayerCount = opacityRegex.numberOfMatches(in: string, options: [], range: NSRange(string.startIndex..<string.endIndex, in: string))
var dumpStr = ""
dump(color, to: &dumpStr)
dumpStr = dumpStr.replacingOccurrences(of: #"^(?:.*\n){\#(4 * opacityLayerCount)}.*?base: "#, with: "", options: .regularExpression)
let opacityModifier = dumpStr.split(separator: "\n")
.suffix(1)
.lazy
.map { $0.replacingOccurrences(of: #"\s+-\s+opacity: "#, with: "", options: .regularExpression) }
.map { CGFloat(Double($0)!) }
.reduce(1, *)
let internalTypeRegex = try! NSRegularExpression(pattern: #"^.*\n.*ColorBox<.*?([A-Za-z0-9]+)>"#)
let matches = internalTypeRegex.matches(in: dumpStr, options: [], range: NSRange(dumpStr.startIndex..<dumpStr.endIndex, in: dumpStr))
guard let match = matches.first, matches.count == 1, match.numberOfRanges == 2 else {
throw ColorConversionError(reason: "Could not parse internalType from \"\(dumpStr)\"")
try! self.init(color: Color.black.opacity(1))
}
self.init(
stringRepresentation: String(dumpStr.prefix { !$0.isNewline }),
internalType: String(dumpStr[Range(match.range(at: 1), in: dumpStr)!]),
opacityModifier: opacityModifier
)
}
}
fileprivate extension UIColor {
static func from(swiftUIDescription description: String, internalType: String) throws -> UIColor {
switch internalType {
case "SystemColorType":
guard let uiColor = UIColor.from(systemColorName: description) else {
throw ColorConversionError(reason: "Could not parse SystemColorType from \"\(description)\"")
}
return uiColor
case "_Resolved":
guard description.range(of: "^#[0-9A-F]{8}$", options: .regularExpression) != nil else {
throw ColorConversionError(reason: "Could not parse hex from \"\(description)\"")
}
let components = description
.dropFirst()
.chunks(of: 2)
.compactMap { CGFloat.decimalFromHexPair(String($0)) }
guard components.count == 4, let cgColor = CGColor(colorSpace: CGColorSpace(name: CGColorSpace.linearSRGB)!, components: components) else {
throw ColorConversionError(reason: "Could not parse hex from \"\(description)\"")
}
return UIColor(cgColor: cgColor)
case "UIColor":
let sections = description.split(separator: " ")
let colorSpace = String(sections[0])
let components = sections[1...]
.compactMap { Double($0) }
.map { CGFloat($0) }
guard components.count == 4 else {
throw ColorConversionError(reason: "Could not parse UIColor components from \"\(description)\"")
}
let (r, g, b, a) = (components[0], components[1], components[2], components[3])
return try UIColor(red: r, green: g, blue: b, alpha: a, colorSpace: colorSpace)
case "DisplayP3":
let regex = try! NSRegularExpression(pattern: #"^DisplayP3\(red: (-?\d+(?:\.\d+)?), green: (-?\d+(?:\.\d+)?), blue: (-?\d+(?:\.\d+)?), opacity: (-?\d+(?:\.\d+)?)"#)
let matches = regex.matches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
guard let match = matches.first, matches.count == 1, match.numberOfRanges == 5 else {
throw ColorConversionError(reason: "Could not parse DisplayP3 from \"\(description)\"")
}
let components = (0..<match.numberOfRanges)
.dropFirst()
.map { Range(match.range(at: $0), in: description)! }
.compactMap { Double(String(description[$0])) }
.map { CGFloat($0) }
guard components.count == 4 else {
throw ColorConversionError(reason: "Could not parse DisplayP3 components from \"\(description)\"")
}
let (r, g, b, a) = (components[0], components[1], components[2], components[3])
return UIColor(displayP3Red: r, green: g, blue: b, alpha: a)
case "NamedColor":
guard description.range(of: #"^NamedColor\(name: "(.*)", bundle: .*\)$"#, options: .regularExpression) != nil else {
throw ColorConversionError(reason: "Could not parse NamedColor from \"\(description)\"")
}
let nameRegex = try! NSRegularExpression(pattern: #"name: "(.*)""#)
let name = nameRegex.matches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
.first
.flatMap { Range($0.range(at: 1), in: description) }
.map { String(description[$0]) }
guard let colorName = name else {
throw ColorConversionError(reason: "Could not parse NamedColor name from \"\(description)\"")
}
let bundleRegex = try! NSRegularExpression(pattern: #"bundle: .*NSBundle <(.*)>"#)
let bundlePath = bundleRegex.matches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
.first
.flatMap { Range($0.range(at: 1), in: description) }
.map { String(description[$0]) }
let bundle = bundlePath.map { Bundle(path: $0)! }
return UIColor(named: colorName, in: bundle, compatibleWith: nil)!
default:
throw ColorConversionError(reason: "Unhandled type \"\(internalType)\"")
}
}
static func from(systemColorName: String) -> UIColor? {
switch systemColorName {
case "clear": return .clear
case "black": return .black
case "white": return .white
case "gray": return .systemGray
case "red": return .systemRed
case "green": return .systemGreen
case "blue": return .systemBlue
case "orange": return .systemOrange
case "yellow": return .systemYellow
case "pink": return .systemPink
case "purple": return .systemPurple
case "primary": return .label
case "secondary": return .secondaryLabel
default: return nil
}
}
convenience init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat, colorSpace: String) throws {
if colorSpace == "UIDisplayP3ColorSpace" {
self.init(displayP3Red: red, green: green, blue: blue, alpha: alpha)
} else if colorSpace == "UIExtendedSRGBColorSpace" {
self.init(red: red, green: green, blue: blue, alpha: alpha)
} else if colorSpace == "kCGColorSpaceModelRGB" {
let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB)!
let components = [red, green, blue, alpha]
let cgColor = CGColor(colorSpace: colorSpace, components: components)!
self.init(cgColor: cgColor)
} else {
throw ColorConversionError(reason: "Unhandled colorSpace \"\(colorSpace)\"")
}
}
func multiplyingAlphaComponent(by multiplier: CGFloat?) -> UIColor {
var a: CGFloat = 0
getWhite(nil, alpha: &a)
return withAlphaComponent(a * (multiplier ?? 1))
}
}
// MARK: Helper extensions
extension StringProtocol {
func chunks(of size: Int) -> [Self.SubSequence] {
stride(from: 0, to: count, by: size).map {
let start = index(startIndex, offsetBy: $0)
let end = index(start, offsetBy: size, limitedBy: endIndex) ?? endIndex
return self[start..<end]
}
}
}
extension Int {
init?(hexString: String) {
self.init(hexString, radix: 16)
}
}
extension FloatingPoint {
static func decimalFromHexPair(_ hexPair: String) -> Self? {
guard hexPair.count == 2, let value = Int(hexString: hexPair) else {
return nil
}
return Self(value) / Self(255)
}
}
Run Code Online (Sandbox Code Playgroud)
注意:虽然这不是手头问题的长期解决方案,因为它取决于Color可能会在某些时候改变的实现细节,但它应该在过渡期间适用于大多数颜色,如果不是所有颜色。
小智 5
@turingtested 更新了您的答案以摆脱长元组崩溃。
extension Color {
func uiColor() -> UIColor {
if #available(iOS 14.0, *) {
return UIColor(self)
}
let scanner = Scanner(string: description.trimmingCharacters(in: CharacterSet.alphanumerics.inverted))
var hexNumber: UInt64 = 0
var r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0, a: CGFloat = 0.0
let result = scanner.scanHexInt64(&hexNumber)
if result {
r = CGFloat((hexNumber & 0xFF000000) >> 24) / 255
g = CGFloat((hexNumber & 0x00FF0000) >> 16) / 255
b = CGFloat((hexNumber & 0x0000FF00) >> 8) / 255
a = CGFloat(hexNumber & 0x000000FF) / 255
}
return UIColor(red: r, green: g, blue: b, alpha: a)
}
}
Run Code Online (Sandbox Code Playgroud)
kon*_*iki -4
这不是 SwiftUI 的工作原理。你想做的事情非常像 UIKit。在 SwiftUI 中,您很少询问视图的任何参数。目前,Color没有任何方法或属性返回其 RGB 值。我怀疑永远不会有。
一般来说,使用 SwiftUI,您需要转到源代码,即首先用于创建颜色的变量。例如:
let r = 0.9
let g = 0.4
let b = 0.7
let mycolor = Color(red: r, green: g, b, opacity: o)
Run Code Online (Sandbox Code Playgroud)
没有这样的事情:
let green = mycolor.greenComponent()
Run Code Online (Sandbox Code Playgroud)
相反,您需要检查变量g(用于创建颜色的变量):
let green = g
Run Code Online (Sandbox Code Playgroud)
我知道这听起来很奇怪,但这就是框架的设计方式。可能需要一些时间来适应它,但你最终会的。
您可能会问,但是如果 mycolor 创建为:
let mycolor = Color.red
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,你运气不好:-(
| 归档时间: |
|
| 查看次数: |
572 次 |
| 最近记录: |