Implementing Dark Mode for iOS: attributed labels workaround
Dark mode for iOS apps became not just a nice-to-have, but a necessity. However, implementing it can sometimes be a hassle. In this article, I’ll cover how to do it as quickly and efficiently as possible.
While developing Alfread, dark theme support was an even more important feature. Alfread is a read-it-later app with a goal to help people read more. Dark mode is an elegant addition so users could read whenever they want.
From a technical point of view, it seemed to be quite an easy task with just three steps:
- Setting Appearance variations in Color assets (pic. 1)
2. Named colors in Interface Builder (pic. 2)
3. Adding a few Swift code snippets to resolve all the cases
However, these steps weren’t enough for our application. One of the components of convenient reading is text formatting.
All our labels use custom stylish fonts and are enhanced with attributes. I didn’t want to bring massive attributes declaration to Swift code and to split UI implementation. That’s why I switched all the labels from Plain to Attributed and put formatting into Storyboards.
What seemed a good solution at first, turned into a problem when implementing the dark mode.
As you may see on the screenshot above, Xcode’s Interface Builder doesn’t associate Named colors with the color editing menu for attributed labels.
It only opens the system palette for RGB or other standard color formats. That’s why such a preset doesn’t provide us automatic colors change when switching iOS theme. Quick research didn’t bring anything rather than moving all the formatting to Swift code and subclassing UILabel. But for our various label styles, it required substantial efforts. Especially as for a pet-project :)
A lazy developer inside me aimed to find a quicker solution. And… spoiler… it was found!
My idea was based on the fact that automatic color change work for Plain labels and all other UI controls. So it might be just a limitation of Interface Builder. I opened Storyboard’s source code to check color implementation for Plain labels and compare it to Attributed ones. A color tag of the Plain label had a name attribute with the specified color name. However, the Attributed label contained text color definition with RGBA and a couple more attributes (see screenshot below).
“Why don’t we replace RGBA attributes with color name right in source code?” — I thought.
If it worked for Plain label, it might help for Attributed. And it worked perfectly. After that, changing a theme was reflected in Attributed labels’ color too. All I needed to do was to search with grep for specific RGBA attributes within the project folder and replace occurrences with corresponding color names.
You may say it’s more a hack than a solution and you may be right. But for me, this is a feature that is not supported just by Interface Builder and conforms to project compilation rules.
Even more, it simplifies implementation significantly.
Written by Tim Velichko, developer of Alfread.