How to convert a String to UIColor in Swift 3.0?

纵然是瞬间 提交于 2020-05-27 06:35:05

问题


I am trying to convert an existing program which uses a list of predefined colors from Objective-C to Swift. The original code used Selector to extract a UIColor based on it name represented as a NSString

#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

-(UIColor *)getColor:(NSString*)colorName
{
    SEL selColor = NSSelectorFromString(colorName);
    NSString *errorMessage = [NSString stringWithFormat:@"Invalid color name: %@ !!!", colorName];
    NSAssert([UIColor respondsToSelector:selColor] == YES, errorMessage);
    UIColor *mycolor = [UIColor performSelector:selColor];
    return mycolor;
}

+ (instancetype)turquoiseColor {
    return UIColorFromRGB(0x40E0D0);
}

+ (instancetype)mediumTurquoiseColor {
    return UIColorFromRGB(0x48D1CC);
}

However, I have been unable to work out how to achieve the same functionality using Swift 3.0, or whether the use of Selector is even the best technique.

func UIColorFromRGB(_ rgbValue: UInt) -> UIColor {
    return UIColor(
        red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
        green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
        blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
        alpha: CGFloat(1.0)
    )
}

extension UIColor {
    public class var turquoise: UIColor { return UIColorFromRGB(0x40E0D0) }
}

extension UIColor {
    public class var mediumTurquoise: UIColor { return UIColorFromRGB(0x48D1CC) }
}

let myColor: UIColor = .turquoise

let name: String = "turquoise"
let colorName = "UIColor.\(name)"
let selector: Selector = NSSelectorFromString(colorName)

let colorSelected: UIColor = UIColor.perform(selector!)

Error: ! No 'perform' candidates produce the expected contextual result type 'UIColor'


回答1:


You can create a Color enum that has a default value of String:

 enum Color: String {
   case red
   case blue
   case green

    var create: UIColor {
       switch self {
          case .red:
            return UIColor.red
        case .blue:
            return UIColor.blue
        case .green:
            return UIColor.green
       }
    }
  }

Since it has a default value of String you can initialize the enum with a string:

  guard let color = Color(rawValue: "red") else { "handle invalid color error"; return } 

 let colorSelected = color.create //// colorSelected is now UIColor.red



回答2:


You can write something similar to your Objective-C code in Swift like this:

extension UIColor {
    @objc(turquoiseColor)
    public class var turquoise: UIColor { return UIColorFromRGB(0x40E0D0) }
}

extension UIColor {
    @objc(mediumTurquoiseColor)
    public class var mediumTurquoise: UIColor { return UIColorFromRGB(0x48D1CC) }
}

let myColor: UIColor = .turquoise

func getColor(_ name: String) -> UIColor? {
    let selector = Selector("\(name)Color")
    if UIColor.self.responds(to: selector) {
        let color = UIColor.self.perform(selector).takeUnretainedValue()
        return (color as! UIColor)
    } else {
        return nil
    }
}

var name: String = "turquoise"
if let color = getColor(name) {
    print(color) //->UIExtendedSRGBColorSpace 0.25098 0.878431 0.815686 1
} else {
    print("color with name:\(name) is unavailable")
}

But using Selector does not seem to be Swifty.

You can simply prepare a Dictionary containing UIColors:

let myColors: [String: UIColor] = [
    "red": .red,
    "white": .white,
    //...
    "turquoise": UIColorFromRGB(0x40E0D0),
    "mediumTurquoise": UIColorFromRGB(0x48D1CC),
]
name = "mediumTurquoise"
if let color = myColors[name] {
    print(color)
} else {
    print("color with name:\(name) is unavailable")
}

Or JustinM's answer is a very good suggestion.




回答3:


Use this extension of UIColor which have two methods for converting RGBA string and Hexadecimal String to UIColor

    extension UIColor {


    //Convert RGBA String to UIColor object
    //"rgbaString" must be separated by space "0.5 0.6 0.7 1.0" 50% of Red 60% of Green 70% of Blue Alpha 100%
    public convenience init?(rgbaString : String){
        self.init(ciColor: CIColor(string: rgbaString))
    }

    //Convert UIColor to RGBA String
    func toRGBAString()-> String {

        var r: CGFloat = 0
        var g: CGFloat = 0
        var b: CGFloat = 0
        var a: CGFloat = 0
        self.getRed(&r, green: &g, blue: &b, alpha: &a)
        return "\(r) \(g) \(b) \(a)"

    }
    //return UIColor from Hexadecimal Color string
    public convenience init?(hexString: String) {

            let r, g, b, a: CGFloat

            if hexString.hasPrefix("#") {
                let start = hexString.index(hexString.startIndex, offsetBy: 1)
                let hexColor = hexString.substring(from: start)

                if hexColor.characters.count == 8 {
                    let scanner = Scanner(string: hexColor)
                    var hexNumber: UInt64 = 0

                    if scanner.scanHexInt64(&hexNumber) {
                        r = CGFloat((hexNumber & 0xff000000) >> 24) / 255
                        g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255
                        b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255
                        a = CGFloat(hexNumber & 0x000000ff) / 255
                        self.init(red: r, green: g, blue: b, alpha: a)
                        return
                    }
                }
            }

            return nil
        }
    // Convert UIColor to Hexadecimal String
    func toHexString() -> String {
        var r: CGFloat = 0
        var g: CGFloat = 0
        var b: CGFloat = 0
        var a: CGFloat = 0
        self.getRed(&r, green: &g, blue: &b, alpha: &a)
        return String(
            format: "%02X%02X%02X",
            Int(r * 0xff),
            Int(g * 0xff),
            Int(b * 0xff)
        )
    }
}



回答4:


Simplification from OOPer's answer. My situation is that I do not have a collection of colour mappings. I have to get the colour from string directly. If it does not exist, use something else. Here is my extension:

import UIKit

extension UIColor { 

    static func colorWith(name:String) -> UIColor? {
        let selector = Selector("\(name)Color")
        if UIColor.self.responds(to: selector) {
            let color = UIColor.self.perform(selector).takeUnretainedValue()
            return (color as? UIColor)
        } else {
            return nil
        }
    }
}

Usage:

self.view.backgroundColor = UIColor.color(name: "red") ?? .blue


来源:https://stackoverflow.com/questions/41162951/how-to-convert-a-string-to-uicolor-in-swift-3-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!