In each of my apps I'm using some kind of a collection of basic information describing the app's general look and layout, which I'm calling stylesheets. With stylesheets, styling an app becomes more easy, more consistent and having one also makes implementing features like themes-support much easier. As I'm using and relying on stylesheets for each of my apps, I'm always searching for a better way to build and use these stylesheets.
My last project used an approach I was pretty happy with, but lately I first stumbled upon an interesting blog post by @natashatherobot and shortly after upon a nice talk by @preynolds_, which both inspired me to rethink and refine my approach once again.
My newest approach makes heavy use of Swift's caseless enums to define namespaced constants in a stylesheet and extensions for applying the stylesheet on your UI elements. (Make sure to read the blog post and watch the talk I linked above to learn more about these concepts!)
This is what an (shortened) example stylesheet could look like with the new approach:
It's basically just a collection of nested enums with static constants. Inside the main
Stylesheet enum, you can define more enums for your stylesheet's categories like Colors, Fonts, Assets or Contexts. In each of these categories, you can get more specific by creating another level of nested enums and so forth.
This approach is very flexible, as you can create and nest enums for all kind of elements/categories you may need in your app in a way that best fits your requirements. It doesn't rely on any standard and can be fully adjusted and extended to your needs.
These are just a few (personal) thinkings behind the basic categories I typically use:
- elements in these categories can be accessed directly, but are preferred to be accessed via Contexts (you could also make a category
privateto enforce this rule)
- name of an element should describe the element itself, not its intended use
- the main outlet when using the stylesheet from anywhere in your app
- each context refers to a scene or even a specific class in your project
- contexts mainly reference constants defined in other categories by redefining them, now named after the specific & intended use
As there is no way to actually create an instance of any of the enums, your stylesheet floats around your whole project as a list of namespaced constants and you don't need to create multiple stylesheet-instances, use a singleton or pass one instance through your whole app from the AppDelegate to each ViewController and View. (looking back embarassed on past approaches)
There are many ways you could then proceed with actually using the Stylesheet and its elements in your project, but I particularly liked the way shown in the talk which inspired me, namely using Extensions.
You could place this extension wherever you want, e.g. directly in the class you want to apply the stylesheet on, or you could even have one extra file for your stylesheet-extensions where you insert a
applyOn method for all of your classes. I've used the one-extension-file approach in my example project and it's really nice not having to search in x amount of different classes for something UI related, but having it all in one central place.
@preynolds_ gives some good additional advice and examples how this approach can make collaborating with designers more efficient in his talk, so if you are working closely with designers, make sure to watch it!
Example project on GitHub
I've created a small example project with a few controllers and views to show off this approach, you can find it on GitHub.
I welcome any positive or negative feedback on this approach and how to further improve stylesheets in Swift. If you have suggestions, tell me on Twitter or via mail and I'll make sure to update this post or write a follow-up.