2016-08-24 6 views
17

Tworzę aplikację do rysowania i chciałbym odnieść się do moich kolorów poprzez użycie wyliczenia. Na przykład byłoby bardziej czysto i wygodniej używać Colors.RedColor zamiast wpisywać wartości za każdym razem, gdy chcę tego koloru czerwonego. Jednak wyliczenia wartości nieprzetworzonych Swiftu nie akceptują UIColor jako typu. Czy istnieje sposób, aby to zrobić z enum lub coś podobnego?Jak utworzyć wyliczenie Swift z wartością UIColor?

+0

"Jednakże, wyliczenia surowej wartości Swifta nie wydają się przyjmować UIColor jako typu" Poprawnie. Wyliczenie wartości surowych może mieć wartość łańcuchową lub literał liczbową. – matt

Odpowiedz

22

zrobić to tak (w zasadzie za pomocą struct jako nazw):

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

I go używać jak:

UIColor.MyTheme.firstColor 

Więc można mieć kolor czerwony wewnątrz niestandardowego tematu.

+0

Dla mnie jest to zdecydowanie najlepsze rozwiązanie! – ixany

20

Jeśli kolor nie jest jednym z tych, zdefiniowane przez UIColor „s metody wygody, można dodać rozszerzenie do 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 
+0

W rzeczywistości w Swift 3 wbudowane kolory są również zmiennymi klasy, dzięki czemu pasują do siebie. – matt

+0

Oto problem: nie mogłem zrobić "static var red: UIColor', ponieważ UIColor ma już właściwość' red' (w Swift 3). Mogę nazwać to czymś innym, jak "redColor", ale wydaje mi się, że złą praktyką jest posiadanie zarówno właściwości "red", jak i 'redColor'. –

+0

Więc nie nazywaj tego' red', nazwij to coś innego jak 'myRed' jeśli twój kolor nie jest "# FF0000" –

9

używam właściwości obliczone, aby rozwiązać ten problem, to jest mój kod

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

wtedy mogę korzystać MyColor tak:

MyColor.navigationBarBackgroundColor.value 
1

Właściwie używam takiego wdrożenia, jest bardzo wygoda dla mnie ze względu na dwie przyczyny, pierwsza mogę użyć wartości dex, a drugi wszystkie kolory w stałym

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

użytkowania

let backgroundGreyColor = ColorPalette.Gray.Medium.cgColor 
0

Jeśli chcesz zwrócić wiele wartości, a następnie użyć poniższego kodu ... to absolutnie pracuję dla mnie ....

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

Jak użyć tego kodu Passing .allvalues["index of your option"] otrzymujesz UIColor w pozycji 0, jak również String value jako 1 pozycji

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

Jak mogę dokonać Swift enum o wartości UIColor?

W ten sposób będzie można dosłownie zrobić enum o wartości 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 = "abcdefABCDEF" 
     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 

z pomocą

0

podstawie @ odpowiedź Jano za zrobiłem poprawę stosując Int jako typ dosłownym:

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 
} 

Zaletą jest to, że nie pozwala duplikaty kolorów (jako prawdziwy wyliczenia), a także popieram alfa .

Jak widać, można utworzyć wiele wyliczeń dla różnych palet/schematów. W przypadku, gdy chcesz widoki, aby móc używać palety, można po prostu dodać Protokół:

protocol Color { 
    var color: UIColor { get } 
} 

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

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

więc w ten sposób można mieć funkcję, która pobiera w protokole:

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) 

Co Lubię też zrobić to dodać vars statycznych dla wygody:

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

który daje czystsze API:

view.backgroundColor = MainPalette.brightRed 

Nazewnictwo można poprawić: musisz wybrać, czy chcesz mieć ładne, wygodne API lub ładne nazwy dla swoich wyrażeń.