2

I want to create a custom palette in IB where you can set colors, and if a color changes in that palette it propagates through the views. I've seen this approach http://natashatherobot.com/xcode-color-palette/, but if in the future, a color of the palette changes, you have to go to every view on the project and change that color. I tried also doing an @IBInspectable but you can't have enums (so you can map an enum to a color). I know i can just define the colors by code and then having an outlet, but the problem is I a have tons of views that I need to subclass just for changing a color like this:

class TestCommonView: CommonView {
@IBOutlet weak var borderView: UIView!
    override func awakeFromNib() {
        super.awakeFromNib()
        borderView.backgroundColor = Colors.fabrica.pastel
    }
} 

Any ideas?

Víctor Albertos
  • 8,093
  • 5
  • 43
  • 71
Godfather
  • 4,040
  • 6
  • 43
  • 70
  • Writing random strings doesnt look good to me... – Godfather Sep 14 '15 at 20:59
  • 1
    @SwiftArchitect it looks promising... I have to put it into a little project and check if it passes the acid test. I mean, once I change a value in the enum's definition, and run it again, the new value should be reflected on runtime. – Adrian Salazar Sep 15 '15 at 07:50
  • I suggest to use `@IBInspectable` as a mere starting point, and tie in with an `@IB_Designable` to show the color on the fly. You would rely on the adapter to put either `Int` or `String` in **IB**, and your **Swift** `Extension` should convert that into an actual color. That color, in turn, can be read and displayed right into **IB**. – SwiftArchitect Sep 15 '15 at 23:26

1 Answers1

2

Reconsidering this statement:

I tried also doing an @IBInspectable but you can't have enums (so you can map an enum to a color).

You can bridge over an @IBInspectable enum using Int this way:

enum ColorPalette:Int {
    case clear = 0
    case teal = 1
    case plum = 2
    case foam = 3
}
var tincture:ColorPalette = .clear

In code, access self.tincture, which is the enum you are after. In Interface Builder, use tinctureAdapter which is an Int, and therefore a de-facto @IBInspectable of type enum.

// Stored IB property
@available(*, unavailable, message="Use tincture programmatically")
@IBInspectable var tinctureAdapter:Int {
    get {
        return self.tincture.rawValue
    }
    set {
        self.tincture = ColorPalette:Int(rawValue: newValue) ?? .clear
    }
}

It may be useful to place this code in a UIColor class Extension. Using the bridge approach, you could also use @Donamite plain-English strings in IB.


Swift 3 Example

@IBDesignable class ColorSwatchView: UIView {

    enum ColorPalette: String {
        case Thistle    = "thistle"
        case Plum       = "plum"
        case Olive      = "olive"
        case Iris       = "iris"

        case Clear      = "clear"
    }

    let namedColors = [
        "thistle": UIColor(red: 216/255, green: 191/255, blue: 216/255, alpha: 1),
        "plum"   : UIColor(red: 221/255, green: 160/255, blue: 221/255, alpha: 1),
        "olive"  : UIColor(red: 128/255, green: 128/255, blue: 0/255, alpha: 1),
        "iris"   : UIColor(red: 3/255, green: 180/255, blue: 200/255, alpha: 1)
    ]

    var tincture:ColorPalette = .Clear

    // Stored IB property
    @available(*, unavailable, message: "Use tincture programmatically")
    @IBInspectable var tinctureName: String? {
        willSet {
            if let color = ColorPalette(rawValue: newValue?.lowercased() ?? "") {
                tincture = color
            }
        }
    }
}

Interface Builder

Make your custom view a child of ColorSwatchView.

enter image description here

Programmatically

override func draw(_ rect: CGRect) {
    let ctx = UIGraphicsGetCurrentContext()
    ctx?.saveGState()
    let uiColor = namedColors[tincture.rawValue] ?? UIColor.clear
    ctx?.setFillColor(uiColor.cgColor)
    ctx?.fill(bounds)
    ctx?.restoreGState()
}

► Find this solution on GitHub and additional details on Swift Recipes.

Community
  • 1
  • 1
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
  • 1
    I think this is a correct answer. Personally I've done similar thing in my project – Ducky Sep 14 '15 at 18:54
  • Until Apple comes up with support, this is the best we have. I'm surprised `Color` and `enum` were not added in Xcode 7, alonside **Swift 2.0** – SwiftArchitect Sep 14 '15 at 20:44