如何将SwiftUI颜色更改为UIColor?

时间:2019-07-29 16:12:53

标签: ios colors uicolor swiftui

尝试将SwiftUI颜色更改为UIColor的实例。

我可以轻松地从UIColor获取RGBA,但是我不知道如何获取“ Color”实例以返回相应的RGB和不透明度值。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void input_store(int* in_file_len, FILE* input_file);

int main(int argc, char* argv[])
{
        //store files into variables
        FILE* input_file = fopen(argv[1], "r");//descriptions to be added
        //count the entire input_file
        if(input_file == NULL)
        {
            printf("failed");
            return 0;
        }
        int in_file_len;
        input_store(&in_file_len, input_file);
        fclose(input_file);
}

void input_store(int* in_file_len, FILE* input_file)
{
        in_file_len = 0;
        char ch = getc(input_file);
        printf("%c\n", ch);
        while(ch != EOF)
        {
                if(ch == '\n')
                {
                        in_file_len++;
                }
                ch = getc(input_file);
        }
        printf("%d\n", *in_file_len); // here
}

...或者也许有更好的方法来完成我想要的。

6 个答案:

答案 0 :(得分:24)

iOS 14 / macOS 10.16

现在有一个新的初始化程序,它需要一个Color并为 iOS 返回一个UIColor,或者为 macOS 返回一个NSColor。所以:

iOS

UIColor(Color.red)

macOS

NSColor(Color.red)

核心图形

UIColor(Color.red).cgColor /* For iOS */
NSColor(Color.red).cgColor /* For macOS */

如果您正在寻找颜色成分,可以找到我有用的扩展名here in this answer

答案 1 :(得分:5)

该解决方案如何?

extension Color {

    func uiColor() -> UIColor {

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

用法:

let uiColor = myColor.uiColor()

这有点骇人听闻,但这至少是一件事情,直到我们得到一个有效的方法为止。这里的键是self.description,它给出颜色的十六进制描述(如果不是动态的,我应该添加)。剩下的只是获取颜色分量并创建UIColor的计算。

答案 2 :(得分:1)

这不是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)

没有类似的内容

let green = mycolor.greenComponent()

相反,您需要检查变量g(用于创建颜色的变量):

let green = g

我知道这听起来很奇怪,但这就是框架的设计方式。可能要花一些时间才能使用它,但最终您会这么做。

您可能会问,但是如果mycolor创建为:

let mycolor = Color.red

在这种情况下,您很不走运:-(

答案 3 :(得分:1)

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

答案 4 :(得分:0)

上面的解决方案对我不起作用,所以我自己尝试了类似的方法:

extension Color {
    var uiColor: UIColor {
        let values = description.split(separator: " ")
        if values.count == 5 {
            return UIColor(red: CGFloat(Double(values[1]) ?? 1), green: CGFloat(Double(values[2]) ?? 1), blue: CGFloat(Double(values[3]) ?? 1), alpha: CGFloat(Double(values[4]) ?? 1))
        }
        return UIColor(red: 1, green: 1, blue: 1, alpha: 1)
    }
}

您可以像这样使用它:

let colour = myColor.uiColor

颜色的描述将所有值包含在字符串中,例如:

"kCGColorSpaceModelRGB 0.509804 0.584314 0.686275 1"

我将其拆分,尝试将值转换为Double,然后转换为CGFloat,如果转换失败,我将1用作每个数字的后备。

我添加了if语句,因为该方法不适用于Color.pink之类的系统颜色,因为它们的描述只是它们的名称。您可以手动捕获这些情况,也可以像我一样忽略它们,而只返回白色。

答案 5 :(得分:0)

当前,SwiftUI API中没有直接提供此功能。但是,我设法使用了调试打印和dump进行了临时初始化。我发现所有其他解决方案都无法说明从名称,捆绑,Color颜色空间,.displayP3,静态系统UIColor初始化的Color或不透明度发生变化的任何颜色。我的解决方案解决了上述所有问题。

extension UIColor {
    convenience init?(color: Color) {
        var description = ""
        debugPrint(color, to: &description)
        let mirror = Mirror(reflecting: color)
        var internalType = "\(type(of: mirror.children.first!.value))".replacingOccurrences(of: "ColorBox<(.+)>", with: "$1", options: .regularExpression)

        var opacity: CGFloat?

        if internalType == "OpacityColor" {
            let regex = try! NSRegularExpression(pattern: #"(\d+% )"#)
            let opacityLayerCount = regex.numberOfMatches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
            var dumpStr = ""
            dump(color, to: &dumpStr)
            dumpStr = dumpStr.replacingOccurrences(of: #"^(?:.*\n){\#(4 * opacityLayerCount)}.*?base: "#, with: "", options: .regularExpression)
            description = String(dumpStr.prefix { !$0.isNewline })

            do {
                let regex = try! NSRegularExpression(pattern: #"^.*\n.*ColorBox<.*?([A-Za-z0-9]+)>"#)
                let matches = regex.matches(in: dumpStr, options: [], range: NSRange(dumpStr.startIndex..<dumpStr.endIndex, in: dumpStr))
                guard let match = matches.first, matches.count == 1, match.numberOfRanges == 2 else { return nil }
                internalType = String(dumpStr[Range(match.range(at: 1), in: dumpStr)!])
            }
            do {
                opacity = dumpStr.split(separator: "\n")
                    .suffix(2)
                    .lazy
                    .map { $0.replacingOccurrences(of: #"\s+-\s+opacity: "#, with: "", options: .regularExpression) }
                    .map { CGFloat(Double($0)!) }
                    .reduce(1, *)
            }
        }

        switch internalType {
        case "SystemColorType":
            let uiColor: UIColor
            switch description {
            case "clear": uiColor = UIColor.clear
            case "black": uiColor = UIColor.black
            case "white": uiColor = UIColor.white
            case "gray": uiColor = UIColor.systemGray
            case "red": uiColor = UIColor.systemRed
            case "green": uiColor = UIColor.systemGreen
            case "blue": uiColor = UIColor.systemBlue
            case "orange": uiColor = UIColor.systemOrange
            case "yellow": uiColor = UIColor.systemYellow
            case "pink": uiColor = UIColor.systemPink
            case "purple": uiColor = UIColor.systemPurple
            case "primary": uiColor = UIColor.label
            case "secondary": uiColor = UIColor.secondaryLabel
            default: return nil
            }
            var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
            uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
            self.init(red: r, green: g, blue: b, alpha: a * (opacity ?? 1))

        case "_Resolved":
            if description.range(of: "^#[0-9A-F]{8}$", options: .regularExpression) != nil {
                let r = CGFloat(Int(String(description[description.index(description.startIndex, offsetBy: 1)...description.index(description.startIndex, offsetBy: 2)]), radix: 16)! / 255)
                let g = CGFloat(Int(String(description[description.index(description.startIndex, offsetBy: 3)...description.index(description.startIndex, offsetBy: 4)]), radix: 16)! / 255)
                let b = CGFloat(Int(String(description[description.index(description.startIndex, offsetBy: 5)...description.index(description.startIndex, offsetBy: 6)]), radix: 16)! / 255)
                let a = CGFloat(Int(String(description[description.index(description.startIndex, offsetBy: 7)...description.index(description.startIndex, offsetBy: 8)]), radix: 16)! / 255)
                let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB)!
                let components = [r, g, b, a]
                let cgColor = CGColor(colorSpace: colorSpace, components: components)!
                if let opacity = opacity {
                    let uiColor = UIColor(cgColor: cgColor).withAlphaComponent(opacity)
                    var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
                    uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
                    self.init(red: r, green: g, blue: b, alpha: a)
                } else {
                    self.init(cgColor: cgColor)
                }
            } else {
                return nil
            }

        case "UIColor":
            let sections = description.split(separator: " ").map { String($0) }
            guard sections.count == 5 else { fatalError() }
            let colorSpace = sections[0]
            let r = CGFloat(Double(sections[1])!)
            let g = CGFloat(Double(sections[2])!)
            let b = CGFloat(Double(sections[3])!)
            let a = CGFloat(Double(sections[4])!)

            if colorSpace == "UIExtendedSRGBColorSpace" {
                self.init(red: r, green: g, blue: b, alpha: a)
            } else if colorSpace == "kCGColorSpaceModelRGB" {
                let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB)!
                let components = [r, g, b, a]
                let cgColor = CGColor(colorSpace: colorSpace, components: components)!
                self.init(cgColor: cgColor)
            } else {
                return nil
            }


        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))
            if let match = matches.first, matches.count == 1, match.numberOfRanges == 4 {
                let components = (1...4).map { CGFloat(Double(String(description[Range(match.range(at: $0), in: description)!]))!)}
                let (r, g, b, a) = (components[0], components[1], components[2], components[3])
                if let opacity = opacity {
                    let uiColor = UIColor(displayP3Red: r, green: g, blue: b, alpha: a).withAlphaComponent(opacity)
                    var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
                    uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
                    self.init(red: r, green: g, blue: b, alpha: a)
                } else {
                    self.init(displayP3Red: r, green: g, blue: b, alpha: a)
                }
            } else {
                return nil
            }

        case "NamedColor":
            if description.range(of: #"^NamedColor\(name: ".*", bundle: nil\)$"#, options: .regularExpression) != nil {
                let regex = try! NSRegularExpression(pattern: #"^NamedColor\(name: "(.*)", bundle: nil\)$"#)
                let matches = regex.matches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
                if let match = matches.first {
                    let name = String(description[Range(match.range(at: 1), in: description)!])
                    if let opacity = opacity {
                        guard let uiColor = UIColor(named: name)?.withAlphaComponent(opacity) else { return nil }
                        var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
                        uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
                        self.init(red: r, green: g, blue: b, alpha: a)
                    } else {
                        self.init(named: name)
                    }
                    break
                } else {
                    return nil
                }
            }
            let regex = try! NSRegularExpression(pattern: #"^NamedColor\(name: "(.*)", bundle: .*NSBundle <(.*)>.*\)$"#)
            let matches = regex.matches(in: description, options: [], range: NSRange(description.startIndex..<description.endIndex, in: description))
            if let match = matches.first, matches.count == 1, match.numberOfRanges == 3 {
                let name = String(description[Range(match.range(at: 1), in: description)!])
                let path = String(description[Range(match.range(at: 2), in: description)!])
                if let opacity = opacity {
                    guard let uiColor = UIColor(named: name, in: Bundle(path: path), compatibleWith: nil)?.withAlphaComponent(opacity) else { return nil }
                    var (r, g, b, a): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
                    uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)
                    self.init(red: r, green: g, blue: b, alpha: a)
                } else {
                    self.init(named: name, in: Bundle(path: path), compatibleWith: nil)
                }

            } else {
                return nil
            }
        default:
            return nil
        }
    }
}

注意:虽然这不是针对当前问题的长期解决方案,但它取决于Color的实现细节,该细节可能会在在某些情况下,它应该可以在大多数(即使不是全部)颜色中使用。