Design System foundations: an Android resource architecture before Compose

Víctor Espejo
BestSecret Tech
Published in
10 min readOct 11, 2022

In our company we want to establish a complete Design System that represent the look & feel of our organization, and, since we do not have a resource architecture in our app, we already have a clear first step.

This resource architecture must fulfilled three conditions:

  • Change the way we want to communicate with our users.
  • Keeping the cohesion of the app.
  • The two others must be accomplished without putting much daily effort.

Note: It can be much more easier done if you are working with Compose, but since it is not very widespread in our app, we will work with the preCompose approach.

So knowing that, we are going to evolve the way we set our visual features in a screen in order to visualize the differences between them.

First step

The first time we try to make an Android app, the views in our .xml files tends to run like this:

Please, don’t do it like this

Well, it looks a bit messy, but it is the ONLY way to customize the view, right… RIGHT!?

Just to clarify, it’s indeed a trap

Okay, let’s say we want to add those properties to every view in your app. Yeah, it will be such a funny work to do. Even better if this work have to be done again with UX changes… Okay, calm down, there is a solution to that, so please, close that Swift tutorial, get out of that Starbucks and continue reading.

Coding with style

The first solution comes with the use of the style, but how can we solve this situation just changing our outfit? Well…, it’s not like that. In Android views we have a way to set a collection of properties in a view, the style.

Okay, I know this feature is only fittable on those properties that are more generic than the canned laughter of 80’s TV shows, but it can be fixed using inheritance in order to avoid duplicity and gain consistency between views.

Well, that wraps it up, doesn’t it? Nope

Come on guys, do you really think it can’t be improved?

To make it on this way is a standard in Android apps development, it reduces a lot of boilerplate BUT, we still need to set the style in EVERY view. That could potentially trigger human errors, like app inconsistency, visual bugs… But on top of that, it also causes what all humans fear the most, BOREDOM.

Coding with themes (Yes, I know this title isn’t even half good than the first latest one)

The next step in this article is to use themes, and what is that? Well let’s describe it like a way to set a collection of properties into views… You might think, isn’t that the same as styles? Well yes, you are right.

Styles vs themes

In the same way that a polysemous word has multiple meanings but it is written the same for whatever the meaning applied; styles and themes are the same, but applied differently.

Did you get the differences?

To sum up: styles are applied to specific views while themes are applied to view groups.

How to apply themes

So… do we need to set the theme property on the root of every activity layout? Well, we could do it that way, but we can also set it programmatically using setTheme, but it must be done BEFORE activity inflation.

Or, in the same way, set it the manifest activity tag.

Okay… does that mean that we need to set a new theme for every activity? It depends, if you are going to use just one theme in your app or at least there is a dominant theme there, then you can just add the theme to the app manifest and it will be used as a base theme in every activity.

You can do it both ways, but you have to ensure that before setting an activity content the activity has to have a theme that define at least the properties defined in Theme.AppCompat (Or Theme.MaterialComponents if you are using material design components), or just at least inherit from this one.

And what happens if you set a theme in the app Manifest and do it so in an activity? Theme overlay occurs, what essentially is a theme merge, but let’s talk a bit further about it.

Theme overlay

The theme overlay consist in a superposition of properties between two themes applied, one as a parent-theme and another as a children-theme. All the children views that have a children-theme set will have the parent-theme properties override by the children-theme properties.

Graphic design is my passion… ok, you can visualize it better here -> (Image from Nick Butcher)

The best way to use it is defining minor themes without any inheritance that defines a little few of modifications that are commonly used in your app. The standard way to named them is ThemeOverlay.AppName.Name.

To visualize the benefits of this option we can use an example: What would you do if you have 2 themes in your application that have to be modified in the same way? If you were to use inheritance you would need to define two more themes with the same set of properties that each inherit from one of the changed themes, instead, if you were to use a themeOverlay you would only need one theme and apply it when needed.

How to use themes

With our theme being applied, we just need to do the most essential thing, to use it. That means use the themes attributes instead of static values:

What you get from using themes is a simple way to change your app UI. Do you want to change your app color palette? No problem, you just have to change the attributes in the theme and all will work fine, no inconsistencies, no visual bugs. It greatly helps you to define a visual standard in your app which is essential to make it easier for users to interact with the app, without dying in the process.

Indeed, this is the way Android views works, components get their properties from the actual theme, and that’s the main reason you must set a Theme that at least inherit from Theme.AppCompat before inflate any view, this is a hard constraint cause if not, those views can’t get anything when they are trying to retrieve the attribute properties. Likewise, when you are trying to inflate a layout that use material views, you need to use a theme that at least inherit from Theme.MaterialComponents cause material design views use an extended set of properties that doesn’t exists in Theme.AppCompat.

Knowing that, you can ask yourself, what can I do if I want to personalize all instances of an Android view to get a property value from a different theme property? You can rewrite the style of those components in your theme and put there the theme property that you want, instead of the default one.

But there is another question, do you can only use those properties that are already created in the themes? Nope.

Define your own theme attributes

You can define your own attributes and just use it as we have seen in the previous example. This definitions are commonly written in a attrs.xml files, and they are not only defined for themes.

Now that we have introduced the custom attributes, you can organize whatever structure you want in your themes, and I would like to present you a way to set up the android resources in a semantic way that can be applied either using themes, by custom attributes, or not.

Extra: Preset — Token resource structure

This structure consist in setting semantic values (tokens), probably many of them, dependant of hardcoded values (presets), probably a few less than the semantic ones. Let’s see an example with colors, where you can think about structure them in two main ways:

  • Option 1: Name the colors by how/where they are used.
  • Option 2: Name the colors by the android role that it is gonna take.

Disadvantages:

  • Option 1: Lot of repeated values in an unstructured file hell. Avoid it at all cost.
  • Option 2: This is like apply Preset-Token structure to android color themes attributes. It can be ok, but we would lost the easy way to change colors in all elements semantically related, we could repeate some colors and we could not recognize the colors by name so we couldn’t recognize the app color palette easily. Moreover, this option can be a bit unflexible if we saw it from the design perception.
First option
Second option
Preset / Token option

What we gain doing a preset-token resource definition is basically the possibility to divide semantically the application, enabling us to change easily many elements related between them and, last but not least, knowing our the values we manage in the app by watching a controlled preset value file instead of one file plenty of duplicated values.

Now that we have defined an app based on themes, let’s go to the next level, a DARKER one indeed.

Beating Dark S̶o̶u̶l̶s̶ mode easily

Themes are the key to supporting dark mode, and one way to do it easily is to split theme properties into dark mode variants/invariants.

Invariant ones would be set in a “Base.Theme” while the variant ones would be set for light/dark mode in a Theme that inherits from the base one; the night variants should be defined inside android night values resource directory “values-night”.

Organizing themes just like that, we can avoid duplicate properties that are not going to be changed from one mode to another, while we separate and automatize the changes between the variant ones when a mode change happens.

Epilogue

From here you can have an idea on how to handle resources, styles and themes in your app, even the ones from material design themes, which are nothing more and nothing less than a customization similar on what we have explained in the article, but in a huge way, based on their UX studies and applied to the material components. If you use them properly you can have great UX behaviours without much effort. Some of those benefits are (Examples are from MaterialDesign 2):

  • Android color tokens
1. The Material Design baseline default theme
2. The Material Design baseline dark theme
  • Android typography tokens
MDC typography tokens
  • Android typography tokens
Distribution of Android components in Shape tokens (Baseline values / Shape customization tool)

But, how are you going to know how to handle every MDC component?

You can get this data from three sources:

Final idea

To sum up, what we want is to set up your app in a way that changes can be done easily and without breaking consistency through the app. What is explained here is just the tip of the iceberg and It isn’t written in stone so feel free to experiment and share whatever you want.

That’s all, I hope you found it interesting and see you later!!

References

Tools

--

--