iOS UIButton backgroundColor You Do It Wrong…

This post is for those who are just starting they journey with iOS and Swift and want to learn some good practices on how to build this nice looking flat UI in modern iOS. Basically i want to talk about rectangle buttons that are filled with color. I saw some really bad implementations of UIButton and now, I want to present you a common mistake, i ofen see in many project even those mature ones.

This image descibes our tutorial code, we have two button first one is done in bad habit and uses backgroundcolor and second one is done using background image property.

Basically backgroundColor property is good thing to use in Interface Builder to see how the button will looks like. But if you try to manage states you will end up with something like this:

1
2
3
4
5
6
7
8
9
@IBAction func buttonHightlight(sender: UIButton!) {

  sender.backgroundColor = UIColor(red: 255.0/255.0, green: 81.0/255.0, blue: 85.0/255.0, alpha: 0.5)
}

@IBAction func buttonNormal(sender: UIButton!) {

  sender.backgroundColor = UIColor(red: 255.0/255.0, green: 81.0/255.0, blue: 85.0/255.0, alpha: 1.0)
}

It is event worst because your states in IB looks very similar to this:

Madness and disaster, seriously that’s not how you want to build your button, highlight state is build in and it’s for free. And of course you only want to call function reponsible for pressing button no additional ones.

To do that we should use backgroundImage property of UIButton, but to not generate any additional assets let’s build two extensions. First one will be reponsibe for generating UIImage from UIColor so we can set it directly from code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import UIKit

extension UIImage {

    class func imageWithColor(color:UIColor?) -> UIImage! {

        let rect = CGRectMake(0.0, 0.0, 1.0, 1.0);

        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)

        let context = UIGraphicsGetCurrentContext();

        if let color = color {

            color.setFill()
        }
        else {

            UIColor.whiteColor().setFill()
        }

        CGContextFillRect(context, rect);

        let image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return image;
    }

}

Second one is not required but is very usefull, and allow you to copy and paste color from eg gimp or photoshop. We are talking about UIColor extension that allow us to use hexadecimal strings as input value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import UIKit

extension UIColor {

    class func colorWithHex(hexString: String?) -> UIColor? {

        return colorWithHex(hexString, alpha: 1.0)
    }

    class func colorWithHex(hexString: String?, alpha: CGFloat) -> UIColor? {

        if let hexString = hexString {

            var error : NSError? = nil

            let regexp = NSRegularExpression(pattern: "\\A#[0-9a-f]{6}\\z",
                options: .CaseInsensitive,
                error: &error)

            let count = regexp.numberOfMatchesInString(hexString,
                options: .ReportProgress,
                range: NSMakeRange(0, countElements(hexString)))

            if count != 1 {

                return nil
            }

            var rgbValue : UInt32 = 0

            let scanner = NSScanner(string: hexString)

            scanner.scanLocation = 1
            scanner.scanHexInt(&rgbValue)

            let red   = CGFloat( (rgbValue & 0xFF0000) >> 16) / 255.0
            let green = CGFloat( (rgbValue & 0xFF00) >> 8) / 255.0
            let blue  = CGFloat( (rgbValue & 0xFF) ) / 255.0

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

        return nil
    }

}

And that’s it, so how do we set our good button ? like this:

1
2
3
4
//good button...
goodButton.backgroundColor = UIColor.clearColor() //reset IB Color
goodButton.setBackgroundImage(UIImage.imageWithColor(UIColor.colorWithHex("#66D269")), forState: .Normal)
goodButton.setBackgroundImage(UIImage.imageWithColor(UIColor.colorWithHex("#66D269", alpha: 0.5)), forState: .Highlighted)

So reassuming, do not use IBAction to modify button color, hightlight state etc. Use backgroundImage and if you don’t want to use assets build them from code using extensions. As always source code on my github page.