Styling with Swift
I am developing iOS apps for over 3 years now. I am asked to apply complete re-designs for 3–4 huge projects in these 3 years, in addition to small once-a-week changes. So I want to state the obvious; requirements and design patterns change really fast and you need to keep up with them in reasonable time frames. But doing that properly is not easy as it seems. I was experimenting different approaches on how to implement a generic styling class for a while and I finally came up something that I am fairly pleased with.
So what are the concerns?
- It should be very easy to use. (No boilerplate.)
- It should be in control of every component style used in my app. (CSS)
- It should be very easy to change any style, globally, at any time.
Let’s divide and conquer.
First, we need to find a simple way to create specific UIColor and UIFont objects that your design needs. Then, we can combine font and color values to introduce pre-defined text styles, as in text editors like iWork Pages or MS Word. And finally, we need to find a way to style your views/layers, just like text.
When you define your styles in one place, like CSS, all you have to do is to simply stick to it and use globally.
Fonts & Colors
I created Font and Color structs to begin with. These can simply be used like:
label.font = Font.withSize(15.0, UIFontWeightRegular) label.textColor = Color.black
How about alpha? It’s not a good idea to have different alpha versions of the same color in your Color struct. If you have 5 colors, and 6 different alpha values, then you would need to define 5 x 6 = 30 colors in your struct, which is really bad. Instead, you can use custom operators to apply alpha values to your color objects.
let colorWithAlpha = Color.red * 0.25 // Or even better: let colorWithAlpha = Color.red * Alpha.low
What defines a text style? Font, or font+color? There are different opinions on that; but to me, it’s font+color. Because you generally use the same color for a specific text style! So I defined a TextStyle struct that contains font and color objects, which can be used like:
titleLabel.style(TextStyle.title) textLabel.style(TextStyle.body) // Namespace your styles: okButton.style(TextStyle.Button.action) deleteButton.style(TextStyle.Button.destructive) cancelButton.style(TextStyle.Button.cancel)
For consistency, you should be using the same colors for same text styles. However, sometimes you might need to change color or alpha components of one text style for one unique component. Again, custom operators are great for this kind of task:
// Changing color of a text style: let rareButtonStyle = TextStyle.Button.action + Color.white // Applying alpha to a text style's color: let rateButtonStyle = TextStyle.Button.action * Alpha.low
View & Layer Style
We covered font, color, alpha and text styles so far. How about background color, corner radius, shadow, borders…? These are definitely not related to text styles so we should define a struct to represent a view’s style.
- borderStyle (color, width)
- shadowStyle (color, opacity, radius, offset)
Using view styles is as easy as using text styles:
Going back to our initial concerns:
- It is indeed easy to use and understand. (+)
- It is capable of controlling every possible style used in the project. (+)
- It is really easy to change things globally as long as you stick to using the same style-guide, everywhere in your project. (+)
This styling approach will most probably satisfy your needs in most projects, in an elegant way. But if it doesn’t, you can easily add new properties to your style structs and implement new requirements.
It’s quite easy to create an interface like mentioned above, using the power of Swift. You can have a look at my sample styling class here.
Note: As you can imagine, most of this can also be implemented in Objective-C. However, the API wouldn’t be so clean and understandable.
All questions and suggestions are welcome!