The interface for UIKit is the same between iOS and tvOS, but the behavior is a little different. The interaction on tvOS is distinctly different than iOS because tvOS doesn’t offer direct interaction. Instead of tapping the screen you use a remote. This is an important point when deciding on how to customize interactive elements.

In this article, I’m going to discuss how you can add color to your buttons on tvOS. This is often required for consistency and branding purposes.

There are a couple of options depending on what your requirements are. The problem is that you might have to try a few approaches to get the desired look.

I will quickly go through what I’ve tried, what worked and what didn’t.

Let start with a simple button that we can experiment with.

class ViewController: UIViewController {
    lazy var button: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Push me", for: .normal)
        button.sizeToFit()
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
}

 

This will give us a standard system button. Here’s what that looks like.

This button looks pretty nice and has a great animation when it’s clicked. The problem is that the button is a bit plain. If you are working on a project, with strong branding, you might want to add some color, to make the UI feel more distinct.

 

Let’s define a primary color. I’ll use dark green as an example.

extension UIColor {
    static let primary = UIColor(red: 0, green: 0.5, blue: 0, alpha: 1.0)
}

Now the first thing you might try is setting the tint color.

button.tintColor = .primary

Unfortunately, this does nothing. 😑

Let’s try the setTitleColor method.

button.setTitleColor(.primary, for: .normal)

This looks better. 🎉  Setting the title color works rather well for a destructive action when set to red. However, it’s more common to want the background color of the button to match the branding color.

 

 

Usually, we can just set the backgroundColor property of the button.

button.backgroundColor = .primary

As you can see, this is not a desirable result. 😳

Using an image for a button works reasonably well actually so we could just set an image containing the desired color.

Here’s some code to create an image with color.

public extension UIImage {
    public class func imageWithColor(_ color : UIColor) -> UIImage {
        let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image!
    }
}

Then we can just set the button color with this.

let image = UIImage.imageWithColor(.primary)
button.setBackgroundImage(image, for: .normal)

Finally, the right background color! For this color, we should probably set the text color to white. We already know how to do this.

button.setTitleColor(.primary, for: .normal)

Another common request is to set the background color only when a button is selected. This is an especially nice touch for screens with multiple buttons. You may have noticed that, so far, we have been setting the button properties for UIControl.State.normal. But, we can, just as easily, set it on the focused and highlighted states.

button.setTitleColor(.black, for: .normal)
button.setTitleColor(.white, for: .focused)
button.setTitleColor(.white, for: .highlighted)
button.setBackgroundImage(UIImage.imageWithColor(.lightGray), for: .normal)
button.setBackgroundImage(UIImage.imageWithColor(.primary), for: .focused)
button.setBackgroundImage(UIImage.imageWithColor(.primary), for: .highlighted)

Conclusion

Adding color to your UIButton elements in tvOS isn’t all that hard, once you know how. The difficulty is that it doesn’t quite work how you might expect, coming from iOS. I hope that my findings, through trial and error, will save someone else some time in getting to the result.

I’d love to hear your feedback, questions or thoughts; find me on twitter @kenboreham
Thanks for reading! 🔥👍