web-dev-qa-db-fra.com

Comment créer une énumération Swift avec la valeur UIColor?

Je fais une application de dessin et je voudrais me référer à mes couleurs en utilisant un enum. Par exemple, il serait plus simple et plus pratique d’utiliser Colors.RedColor au lieu de saisir des valeurs à chaque fois que je veux cette couleur rouge. Cependant, les enums de valeurs brutes de Swift ne semblent pas accepter UIColor comme type. Y a-t-il un moyen de faire cela avec une enum ou quelque chose de similaire?

20
A Tyshka

Je le fais comme ça (en utilisant essentiellement une structure comme un espace de noms):

extension UIColor {
  struct MyTheme {
    static var firstColor: UIColor  { return UIColor(red: 1, green: 0, blue: 0, alpha: 1) }
    static var secondColor: UIColor { return UIColor(red: 0, green: 1, blue: 0, alpha: 1) }
  }
}

Et vous l'utilisez comme:

UIColor.MyTheme.firstColor

Ainsi, vous pouvez avoir une couleur rouge dans votre thème personnalisé. 

39
FranMowinckel

Si votre couleur n'est pas l'une de celles définies par la méthode pratique de UIColor, vous pouvez ajouter une extension à UIColor:

extension UIColor {
    static var firstColor: UIColor  { return UIColor(red: 1, green: 0, blue: 0, alpha: 1) }
    static var secondColor: UIColor { return UIColor(red: 0, green: 1, blue: 0, alpha: 1) }
}

// Usage
let myColor = UIColor.firstColor
27
Code Different

J'utilise des propriétés calculées pour résoudre ce problème, c'est mon code

enum MyColor {
    case navigationBarBackgroundColor
    case navigationTintCololr
}

extension MyColor {
    var value: UIColor {
        get {
            switch self {
            case .navigationBarBackgroundColor:
                return UIColor(red: 67/255, green: 173/255, blue: 247/255, alpha: 1.0)
            case .navigationTintCololr:
                return UIColor.white
            }
        }
    }
}

alors je peux utiliser MyColor comme ceci:

MyColor.navigationBarBackgroundColor.value
12
Teng

Comment créer une énumération Swift avec la valeur UIColor?

Voici comment créer littéralement une énumération avec une valeur UIColor:

import UIKit

final class Color: UIColor, RawRepresentable, ExpressibleByStringLiteral
{
    // MARK:- ExpressibleByStringLiteral

    typealias StringLiteralType = String

    convenience init(stringLiteral: String) {
        guard let (a,r,g,b) = Color.argb(hexColor: stringLiteral) else {
            assertionFailure("Invalid string")
            self.init(red: 0, green: 0, blue: 0, alpha: 0)
            return
        }
        self.init(red: r, green: g, blue: b, alpha: a)
    }

    // MARK:- RawRepresentable

    public typealias RawValue = String

    convenience init?(rawValue: RawValue) {
        guard let (a,r,g,b) = Color.argb(hexColor: rawValue) else { return nil }
        self.init(red: r, green: g, blue: b, alpha: a)
    }

    var rawValue: RawValue {
        return hexString()
    }

    // MARK:- Private

    /// Return color components in range [0,1] for hexadecimal color strings.
    /// - hexColor: case-insensitive string with format RGB, RRGGBB, or AARRGGBB.
    private static func argb(hexColor: String) -> (CGFloat,CGFloat,CGFloat,CGFloat)?
    {
        let hexAlphabet = "0123456789abcdefABCDEF"
        let hex = hexColor.trimmingCharacters(in: CharacterSet(charactersIn: hexAlphabet).inverted)
        var int = UInt32()
        Scanner(string: hex).scanHexInt32(&int)
        let a, r, g, b: UInt32
        switch hex.count {
        case 3: (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) // RGB
        case 6: (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) // RRGGBB
        case 8: (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) // AARRGGBB
        default: return nil
        }
        return (CGFloat(a)/255, CGFloat(r)/255, CGFloat(g)/255, CGFloat(b)/255)
    }

    private func hexString() -> String {
        var red:   CGFloat = 0
        var green: CGFloat = 0
        var blue:  CGFloat = 0
        var alpha: CGFloat = 0
        if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            return String(format: "#%02X%02X%02X%02X", UInt8(red * 255), UInt8(green * 255), UInt8(blue * 255), UInt8(alpha * 255))
        }
        assertionFailure("Invalid colour space.")
        return "#F00"
    }
}

enum Colors: Color {
    case red = "#F00"
//    case blue = "#F00" // Raw value for enum case is not unique
}

let color3 = Color(rawValue: "#000") // RGB
let color6 = Color(rawValue: "#123456") // RRGGBB
let color8 = Color(rawValue: "#12345678") // AARRGGBB
print(Colors(rawValue:"#F00") as Any) // red
print(Colors(rawValue:"#FF0000") as Any) // red
print(Colors(rawValue:"#FFFF0000") as Any) // red
print(Colors(rawValue:"#ABC") as Any) // nil because it’s not a member of the enumeration
// print(Colors(rawValue:"#XYZ") as Any) // assertion on debug, black on release
print(Colors.red) // red
print(Colors.red.rawValue) // UIExtendedSRGBColorSpace 1 0 0 1

Avec l'aide de 

4
Jano

En fait, j’utilise une telle implémentation, c’est très pratique pour moi pour deux raisons: premièrement, je peux utiliser la valeur dex et une autre toutes couleurs confondues 

import UIKit

struct ColorPalette {
struct Gray {
    static let Light = UIColor(netHex: 0x595959)
    static let Medium = UIColor(netHex: 0x262626)
}
}

extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
    assert(red >= 0 && red <= 255, "Invalid red component")
    assert(green >= 0 && green <= 255, "Invalid green component")
    assert(blue >= 0 && blue <= 255, "Invalid blue component")

    self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
}

convenience init(netHex: Int) {
    self.init(red: (netHex >> 16) & 0xff, green: (netHex >> 8) & 0xff, blue: netHex & 0xff)
}
}

usage 

let backgroundGreyColor = ColorPalette.Gray.Medium.cgColor
1

Si vous voulez renvoyer plusieurs valeurs, utilisez le code ci-dessous ... c'est absolument travailler pour moi ....

enum GetDriverStatus : String {
    case ClockIn            = "Clock In"
    case TripStart          = "Trip Start"
    case BeaconTouchPlant   = "Beacon Touch Plant"
    case PickUp             = "Pick Up"
    case BeaconTouchSite    = "Beacon Touch Site"
    case BeaconLeftSite     = "Beacon Left Site"
    case DropOff            = "Drop Off"
    case BreakIn            = "Break In"
    case BreakOut           = "Break Out"
    case TripEnd            = "Trip End"
    case DayEnd             = "Day End"
    //case ClockOut           = "Clock Out"

    //Get data from ID
    static var allValues: [GetDriverStatus] {
        return [
            .ClockIn,
            .TripStart,
            .BeaconTouchPlant,
            .PickUp,
            .BeaconTouchSite,
            .BeaconLeftSite,
            .DropOff,
            .BreakIn,
            .BreakOut,
            .TripEnd,
            .DayEnd
        ]
    }

    //Get Color
    var colorAndStatus: (UIColor,String) {
        get {
            switch self {
            case .ClockIn,.TripStart: //Idle
                return (UIColor(red: 248/255, green: 39/255, blue: 71/255, alpha: 1.0),"Idle") //dark pink-red
            case .BeaconTouchPlant,.PickUp:
                return (UIColor(red: 46/255, green: 180/255, blue: 42/255, alpha: 1.0),"Picking up") //Green
            case .BeaconTouchSite:
                return (UIColor(red: 252/255, green: 172/255, blue: 0/255, alpha: 1.0),"On site") //orange
            case .DropOff,.BeaconLeftSite:
                return (UIColor(red: 12/255, green: 90/255, blue: 255/255, alpha: 1.0),"Dropping off") //blue
            case .BreakIn,.BreakOut:
                return (UIColor(red: 151/255, green: 151/255, blue: 151/255, alpha: 1.0),"On break") //warm-grey-two
            case .TripEnd:
                return (UIColor.black,"Trip end")
            case .DayEnd:
                return (UIColor.black,"Done for the day")
            }
        }
    }
} 

Comment utiliser ce code En passant .allvalues["index of your option"] vous obtenez UIColor à la position 0 ainsi que String value à la position 1

GetDriverStatus.allValues[1].colorAndStatus.0 //UIColor.Black
GetDriverStatus.allValues[2].colorAndStatus.1 //"Picking up"
0
kuldip bhalodiya

Sur la base de la réponse de @ Jano, j'ai apporté une amélioration en utilisant Int comme type littéral:

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
}

L'avantage est qu'il ne permet pas les couleurs en double (en tant que véritable énumération) et que je supporte également l'alpha.

Comme vous pouvez le constater, vous pouvez créer plusieurs énumérations pour différents palettes/modèles. Si vous souhaitez que les vues puissent utiliser n’importe quelle palette, vous pouvez simplement ajouter un protocole: 

protocol Color {
    var color: UIColor { get }
}

extension MainPalette: Color {
    var color: UIColor {
        return rawValue
    }
}

extension FeatureXPalette: Color {
    var color: UIColor {
        return rawValue
    }
}

de cette façon, vous pouvez avoir une fonction qui prend dans le protocole:

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)

Ce que j'aime aussi faire, c'est ajouter des vars statiques pour plus de commodité:

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

cela vous donne une api plus propre:

view.backgroundColor = MainPalette.brightRed

Le nommage peut être amélioré: vous devez choisir si vous voulez un api pratique ou un nommage agréable pour vos enums.

0
Eric

Cela peut être fait beaucoup plus succinctement (et devrait):

extension UIColor
{
    static let myColor = UIColor(displayP3Red: 0.0, green: 0.7, blue: 0.0, alpha: 1.0)
}

(Toute autre méthode renvoyant UIColor convient également, il n'est pas nécessaire que ce soit displayP3Red)

Usage:

let someColor: UIColor = .myColor
0
HenryRootTwo