Creating Clean and Reusable Views in Swift with Custom Themes using Factories

Fadie Hannona
3 min readApr 10, 2018

--

Have you ever tried to create a custom reusable view which needs to have different themes? Probably quite a lot of the time I would imagine.

You might write the logic to differentiate when to use each one within the custom UI element class. What if you have several different themes for one element?

You can see how quickly that can get out of control. Before you know it, there’s more code written than you bargained for which can be prone to bugs and crashes and that class becomes way more of an effort to understand.

It becomes annoying to build on top of and you might need to configure instances of it within the ViewController it lives in, adding more respsonbility to ViewControllers.

There’s a better way…

Let‘s say we wanted to create two UIButtons, that share the same features but differ in colour and have distinct labels. A red button that says “Cancel,” and a button with no background and a black border that says “Next.”

First let’s define a protocol with variables that define the properties that will differ based on our user interface needs. In our case, we would define the following:

protocol ButtonTheme {
var label: String { get set }
var backgroundColor: UIColor { get }
var tintColor: UIColor { get }
}

We can create the two themes which adhere to this protocol.

struct RedButtonTheme: ButtonTheme {
var backgroundColor: UIColor = .red
var tintColor: UIColor = .white
var label: String
init(label: String) {
self.label = label
}
}
struct ClearButtonTheme: ButtonTheme {
var backgroundColor: UIColor = .clear
var tintColor: UIColor = .black
var label: String
init(label: String) {
self.label = label
}
}

Now we need a button.

class LargeButton: UIButton {    var theme: ButtonTheme? { 
didSet {
styleButton()
}
}
private func styleButton() {
if let theme = theme {
backgroundColor = theme.backgroundColor
tintColor = theme.tintColor
setTitle(theme.label, for: .normal)
}
}
}

If we connect two @IBOutlets in a ViewController, all we have to do to configure them is:

nextButton.theme = ClearButtonTheme(label: "Next")
cancelButton.theme = RedButtonTheme(label: "Cancel")

That’s a lot nicer…

In more specific cases, you could have a theme protocol like this.

protocol TextFieldTheme {
var keyboardType: UIKeyboardType { get }
var autocorrectionType: UITextAutocorrectionType { get }
var delegate: UITextFieldDelegate { get }
var capitalizationType: UITextAutocapitalizationType { get }
var placeholderText: String { get set }
var value: String { get set }
}

Seperating themes into their own files defining the protocol at the top followed by the theme definitions underneath works nicely I’ve found. It’s the closest I’ve felt to having something similar to CSS classes in iOS.

Advantages

This way of creating custom reusable views takes responsibility of configuring UI out of ViewControllers and the elements themselves, into factories. You now have the ability to have create multiple UI themes and not get bloat within these classes.

You could have 1000 different themes for a label and your label class will still look good. Hell, you can now move things like UITextFieldDelegates out of ViewControllers if you wanted to. A nicer, cleaner and more modular approach. Reusability achieved.

I’ve found it also has the added advantage of less bugs, views become more managable and can be extended upon with ease. Also I’m sure you don’t have to be reminded but anything to prevent massive view controllers is usually welcome too.

I had fun discovering this. Let me know what you think below in the comments.

--

--

Fadie Hannona

iOS Developer @ Deloitte Digital / Exploring Calisthenics.