How can I make a Swift enum with UIColor value?

前端 未结 9 746
深忆病人
深忆病人 2020-12-16 09:37

I\'m making a drawing app and I would like to refer to my colors through use of an enum. For example, it would be cleaner and more convenient to use Colors.RedColor

9条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-16 10:02

    Based on @Jano's answer I made an improvement by using Int as the literal type:

    import UIKit
    
    public final class Colors: UIColor {
    
    }
    
    extension Colors: ExpressibleByIntegerLiteral {
        public typealias IntegerLiteralType = Int
    
        public convenience init(integerLiteral value: Int) {
            let red = CGFloat((value & 0xFF0000FF) >> 24) / 0xFF
            let green = CGFloat((value & 0x00FF00FF) >> 16) / 0xFF
            let blue = CGFloat((value & 0x0000FFFF) >> 8) / 0xFF
            let alpha = CGFloat(value & 0x00FF00FF) / 0xFF
    
            self.init(red: red, green: green, blue: blue, alpha: alpha)
        }
    }
    
    extension Colors: RawRepresentable {
        public typealias RawValue = Int
    
        public var rawValue: RawValue {
            return hex
        }
    
        public convenience init?(rawValue: RawValue) {
            self.init(integerLiteral: rawValue)
        }
    }
    
    fileprivate extension UIColor {
        var hex: Int {
            var fRed: CGFloat = 0
            var fGreen: CGFloat = 0
            var fBlue: CGFloat = 0
            var fAlpha: CGFloat = 0
            if self.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha) {
                let red = Int(fRed * 255.0)
                let green = Int(fGreen * 255.0)
                let blue = Int(fBlue * 255.0)
                let alpha = Int(fAlpha * 255.0)
                let rgb = (alpha << 24) + (red << 16) + (green << 8) + blue
                return rgb
            } else {
                return 0x000000
            }
        }
    }
    
    public enum MainPalette: Colors {
        case red = 0xFF0000ff
        case white = 0xFFFFFFFF
    }
    
    public enum FeatureXPalette: Colors {
        case blue = 0x024F9Eff
    //    case bluish = 0x024F9Eff // <- Can't do
        case red = 0xFF0000ff
    }
    

    The advantage is that it doesn't allow duplicate colors (as a true enum) and also I support alpha.

    As you can see, you can create multiple enums for different palettes/schemes. In the case you want views to be able to use any palette, you can just add a protocol:

    protocol Color {
        var color: UIColor { get }
    }
    
    extension MainPalette: Color {
        var color: UIColor {
            return rawValue
        }
    }
    
    extension FeatureXPalette: Color {
        var color: UIColor {
            return rawValue
        }
    }
    

    so that way you can have a function that takes in the protocol:

    func printColorEquality(color1: Color, color2: Color) {
        print(color1.color == color2.color)
    }
    
    let red1: Color = MainPalette.red
    let red2: Color = FeatureXPalette.red
    
    printColorEquality(color1: red1, color2: red2)
    

    What I also like to do is add static vars for convenience:

    extension MainPalette {
        public static var brightRed: UIColor {
            return MainPalette.red.color
        }
    }
    

    that gives you a cleaner api:

    view.backgroundColor = MainPalette.brightRed
    

    Naming can be improved: you have to choose if you want a nice convenience api or nice naming for your enums.

提交回复
热议问题