· 6 min read

UIColor best practices in Swift


Learn what are color models, how to convert hex values to UIColor and back, generate random colors, where to find beautiful palettes.

What are color models and color spaces?

A color model is a method of describing a color.

  • RGB - Red+Green+Blue
  • HSB - Hue+Saturation+Brightness

There are several other color models, but if you are dealing with iOS colors you should be familiar with these two above. Usually you are going to work with the RGBA & HSBA color models which are basically the same as above extended with the alpha channel where the letter A stands for that. šŸ˜‰

A color space is the set of colors which can be displayed or reproduced in a medium (whether stored, printed or displayed). For example, sRGB is a particular set of intensities for red, green and blue and defines the colors that can be reproduced by mixing those ranges of red, green and blue.

Enough from the theory, letā€™s do some color magic! šŸ’«šŸ’«šŸ’«

How to work with UIColor objects using RGBA and HSBA values in Swift?

Do you remember the old Paint program from old-school Windows times?

Iā€™ve used Microsoft Paint a lot, and I loved it. šŸ˜…

Back then without any CS knowledge I was always wondering about the numbers between 0 and 255 that I had to pick. If you are working with RGB colors you usually define your color the same way, except that in iOS the values are between 0 and 1, but thatā€™s just a different representation of the fraction of 255.

So you can make a color with RGB codes using the same logic.

UIColor(
    red: CGFloat(128)/CGFloat(255),
    green: CGFloat(128)/CGFloat(255),
    blue: CGFloat(128)/CGFloat(255),
    alpha: 1
)
// this is just about the same gray color but it's more readable
UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1)

See? Pretty easy, huh? šŸ‘

Alternatively you can use HSB values, almost the same logic applies for those values, except that hue goes from 0 ā€™til 360 (because of the actual color wheel), however saturation and brightness are measured in a ā€œpercent likeā€ format 0-100, so you have to think about these numbers if you map them to floating point values.

UIColor(hue: CGFloat(120)/CGFloat(360), saturation: 0.5, brightness: 0.5, alpha: 1)
UIColor(hue: 0.3, saturation: 0.5, brightness: 0.5, alpha: 1)

Now letā€™s reverse the situation and let me show you how to get back these components from an actual UIColor instance with the help of an extension.

public extension UIColor {
    public var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        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)
    }

    public var hsba: (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) {
        var h: CGFloat = 0
        var s: CGFloat = 0
        var b: CGFloat = 0
        var a: CGFloat = 0
        self.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
        return (h, s, b, a)
    }
}

So here it is how to read the red, green blue slash hue saturation brightness and alpha components from a UIColor. With this little neat extension you can simply get the component values and use them through their proper names.

UIColor.yellow.rgba.red
UIColor.yellow.hsba.hue

How to convert HEX colors to RGB and vica versa for UIColor objects in Swift?

iOS developer 101 course, first questions:

  • How the fuck can I create a UIColor from a hex string?
  • How to convert a hex color to a UIColor?
  • How to use a hext string to make a UIColor?

Ok, maybe these are not the first questions, but itā€™s definitely inside common ones. The answer is pretty simple: through an extension. I have a really nice solution for your needs, which will handle most of the cases like using only 1, 2, 3 or 6 hex values.

public extension UIColor {

    public convenience init(hex: Int, alpha: CGFloat = 1.0) {
        let red = CGFloat((hex & 0xFF0000) >> 16) / 255.0
        let green = CGFloat((hex & 0xFF00) >> 8) / 255.0
        let blue = CGFloat((hex & 0xFF)) / 255.0

        self.init(red: red, green: green, blue: blue, alpha: alpha)
    }

    public convenience init(hex string: String, alpha: CGFloat = 1.0) {
        var hex = string.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

        if hex.hasPrefix("#") {
            let index = hex.index(hex.startIndex, offsetBy: 1)
            hex = String(hex[index...])
        }

        if hex.count < 3 {
            hex = "\(hex)\(hex)\(hex)"
        }

        if hex.range(of: "(^[0-9A-Fa-f]{6}$)|(^[0-9A-Fa-f]{3}$)", options: .regularExpression) != nil {
            if hex.count == 3 {

                let startIndex = hex.index(hex.startIndex, offsetBy: 1)
                let endIndex = hex.index(hex.startIndex, offsetBy: 2)

                let redHex = String(hex[..<startIndex])
                let greenHex = String(hex[startIndex..<endIndex])
                let blueHex = String(hex[endIndex...])

                hex = redHex + redHex + greenHex + greenHex + blueHex + blueHex
            }

            let startIndex = hex.index(hex.startIndex, offsetBy: 2)
            let endIndex = hex.index(hex.startIndex, offsetBy: 4)
            let redHex = String(hex[..<startIndex])
            let greenHex = String(hex[startIndex..<endIndex])
            let blueHex = String(hex[endIndex...])

            var redInt: CUnsignedInt = 0
            var greenInt: CUnsignedInt = 0
            var blueInt: CUnsignedInt = 0

            Scanner(string: redHex).scanHexInt32(&redInt)
            Scanner(string: greenHex).scanHexInt32(&greenInt)
            Scanner(string: blueHex).scanHexInt32(&blueInt)

            self.init(red: CGFloat(redInt) / 255.0,
                      green: CGFloat(greenInt) / 255.0,
                      blue: CGFloat(blueInt) / 255.0,
                      alpha: CGFloat(alpha))
        }
        else {
            self.init(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
        }
    }

    var hexValue: String {
        var color = self

        if color.cgColor.numberOfComponents < 4 {
            let c = color.cgColor.components!
            color = UIColor(red: c[0], green: c[0], blue: c[0], alpha: c[1])
        }
        if color.cgColor.colorSpace!.model != .rgb {
            return "#FFFFFF"
        }
        let c = color.cgColor.components!
        return String(format: "#%02X%02X%02X", Int(c[0]*255.0), Int(c[1]*255.0), Int(c[2]*255.0))
    }
}

Here is how you can use it with multiple input variations:

let colors = [
    UIColor(hex: "#cafe00"),
    UIColor(hex: "cafe00"),
    UIColor(hex: "c"),
    UIColor(hex: "ca"),
    UIColor(hex: "caf"),
    UIColor(hex: 0xcafe00),
]
let values = colors.map { $0.hexValue }
print(values) //["#CAFE00", "#CAFE00", "#CCCCCC", "#CACACA", "#CCAAFF", "#CAFE00"]

As you can see Iā€™ve tried to replicate the behavior of the CSS rules, so you will have the freedom of less characters if a hext string is like #ffffff (you can use just f, because # is optional). Also you can provide integers as well, thatā€™s just a simple ā€œoverloadedā€ convenience init method.

Also .hexValue will return the string representation of a UIColor instance. šŸ‘šŸ‘šŸ‘

How to generate a random UIColor in Swift?

This is also a very common question for beginners, I donā€™t really want to waste the space here by deep explanation, arc4random() is just doing itā€™s job and the output is a nice randomly generated color.

public extension UIColor {
    public static var random: UIColor {
        let max = CGFloat(UInt32.max)
        let red = CGFloat(arc4random()) / max
        let green = CGFloat(arc4random()) / max
        let blue = CGFloat(arc4random()) / max

        return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
    }
}

How to create a 1x1 pixel big UIImage object with a single solid color in Swift?

Iā€™m using this trick to set the background color of a UIButton object. The reason for this is state management. If you press the button the background image will be darker, so there will be a visual feedback for the user. However by setting the background color directly of a UIButton instance wonā€™t work like this, and the color wonā€™t change at all on the event. šŸ‘†

public extension UIColor {
    public var imageValue: UIImage {
        let rect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()!
        context.setFillColor(self.cgColor)
        context.fill(rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

The snippet above will produce a 1x1 pixel image object from the source color. You can use that anywere, but here is my example with a button background:

button.setBackgroundImage(UIColor.red.imageValue, for: .normal)

Online color palettes

You canā€™t find the right color? No problem, these links will help you to choose the proper one and to get some inspiration. Also if you are looking for flat UI colors or material design colors these are the right links where you should head first.

A personal thing of mine: dear designers, please never ever try to use material design principles for iOS apps. Thank you. HIG

Convert colors online

Finally there are some great online color converter tools, if you are looking for a great one, you should try these first.

Managing UIColors

If your app target is iOS 11+ you can use asset catalogs to organize your color palettes, but if you need to go below iOS 11, Iā€™d suggest to use an enum or struct with static UIColor properties. Nowadays Iā€™m usually doing something like this.

class App {
    struct Color {
        static var green: UIColor { return UIColor(hex: 0x4cd964) }
        static var yellow: UIColor { return UIColor(hex: 0xffcc00) }
        static var red: UIColor { return UIColor(hex: 0xff3b30) }
    }

    /* ... */
}

App.Color.yellow

Usually Iā€™m grouping together fonts, colors etc inside structs, but this is just one way of doing things. You can also use something like R.swift or anything that you prefer.

Thatā€™s it for now, I think Iā€™ve covered most of the basic questions about UIColor.

Feel free to contact me if you have a topic or suggestion that youā€™d like to see covered here in the blog. Iā€™m always open for new ideas. šŸ˜‰

Related posts

· 8 min read

10 little UIKit tips you should know


In this article I've gathered my top 10 favorite modern UIKit tips that I'd definitely want to know before I start my next project.

· 5 min read

Building input forms for iOS apps


Learn how to build complex forms with my updated collection view view-model framework without the struggle using Swift.

· 5 min read

Custom UIView subclass from a xib file


Do you want to learn how to load a xib file to create a custom view object? Well, this UIKit tutorial is just for you written in Swift.

· 4 min read

Custom views, input forms and mistakes


Just a little advice about creating custom view programmatically and the truth about why form building with collection views sucks.

Practical Server Side Swift cover image

Get the Practical Server Side Swift book

Swift on the server is an amazing new opportunity to build fast, safe and scalable backend apps. Write your very first web-based application by using your favorite programming language. Learn how to build a modular blog engine using the latest version of the Vapor 4 framework. This book will help you to design and create modern APIs that'll allow you to share code between the server side and iOS. Start becoming a full-stack Swift developer.

Available on Gumroad