Managing your android app iconography

Jorge Muci
Apr 22 · 7 min read

Use application drawables with theme attributes to seamlessly support multiple app themes or different build variants.

Image for post
Image for post

A lot of things have changed since Android Lollipop was released in regards to how visual assets are handled in apps. In addition to vectorDrawables, which was a huge change to the platform, there are other features that make application theming and styling easier to implement and maintain. This article will focus on using theme attributes with vector drawables to show how to easily support different app branding and multiple themes, like dark mode, in a straightforward way.

The approach described in this post is what we are currently applying in Tuenti to easily maintain icons in a huge project with multiple brands.

One asset to rule them all

In a nutshell, what you’ll end up with after reading this post are these automagically styled icons!

Image for post
Image for post

This post assumes your minSdk is 21 or higher and you’re already using vectorDrawables in your app. If that’s not the case then consider migrating your pngs to vectorDrawables, unless for some diabolical reason you enjoy the hell of dealing with pngs in a multi-density screen world. Seriously, just migrate.

Show me the code

What's a Theme?

Theme attributes to the rescue

And then in your res/values/styles.xml file you can reference this new created theme attribute and assign a color value:

Now, how can theme attributes be used with vectorDrawables so your icons automatically change appearance when the app theme is changed or a different app build variant is compiled?

This is frequently how you’ll find most of the vector XML files in an app.

Notice how the color for each vector <path> is hardcoded with a specific color like, android:fillColor=”#3282b8". This kind of code should be removed from the vector assets and a semantic color should be used instead. Semantic colors are just theme attributes that represent reusable colors with specific meaning.

The end goal is to define a set of semantic colors that can be referenced from the app’s vector assets, as shown here.

With the semantic colors defined, the vector assets will automatically change color whenever the app’s theme is changed to a different primaryColor or another build variant is compiled with a different colors.xml palette.

You might be thinking you can achieve the same results by defining colors for your drawables in your layouts or dynamically with code. You wouldn’t be wrong. But that approach has some limitations. Say your code looks like this:

<android.support.v7.widget.AppCompatImageView
android:id="@+id/my_appcompat_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/my_image"
android:tint="@color/blue"/>

or this:

val drawable = getResources().getDrawable(R.drawable.my_image)
val wrapDrawable = DrawableCompat.wrap(normalDrawable)
DrawableCompat.setTint(wrapDrawable, getResources().getColor(R.color.colorPrimaryLight))
  • First of all, coloring assets that way doesn’t’ change the color of the icon. All it does is paint a color on top. That means if you use a color with transparency for the asset you won’t get the results you expect. There are workarounds, of course. But, the point is to keep things as simple as possible.
  • Secondly, when you color drawables that way you can only use one color. So, if your vectorDrawable has several paths with different colors you won’t be able to change the color for each vector path.

Define a set of semantic colors

Image for post
Image for post
An example semantic color palette by the design team

This is also great if you work with a design team, because you can define your semantic colors along with them. You can then make your design directly using the semantic palette. Consequently, when your drawable is imported you won’t have to worry if it’s going to be used in dark mode or any other brand variant of your app. Restyling your app becomes a piece of cake.

Let's get dynamic!

Now from your view, lets say MainActivity.kt:

And that's it. You can reuse your themes and easily apply them dynamically for specific views on your layout.

Multi-flavored app? No problem

Let’s say there are a couple brands defined as product flavors for the project in your app’s build.gradle.

Sample flavors for multi-brand Android project

Each brand has a different color palette in the colors.xml file.

Image for post
Image for post
Color palettes for every build flavor/brand in your project

When you have the color palettes defined, you just have to redefine the app themes to reference the new colors. So, in each newly created brand folder you just need to add a new file, that can be called something like brand_themes.xml. Then set the app themes to use it for coloring the icons in the different app variants.

Image for post
Image for post

With everything in place, you can now compile your different app variants and see the results.

Image for post
Image for post
Multi brand project compilation

Android Lint is your friend

  • Rely on yourself or your teammates to never use hardcoded color values in your assets, layouts, or views. And be hyper vigilant about hardcoded values during code reviews (not the best option).

or

  • You can use android tooling to detect issues automatically with linting. Check out this great post about using custom linting rules to warn about hardcoded colors in your project. What’s more, you can also detect if you’re using colors like white, blue, red, etc, across your app instead of the semantic colors defined such as colorPrimary, colorDanger, colorWarning, etc.

One more thing: VectorCompat!

android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}

And when setting your drawables directly from a layout.xml file use app:srcCompat=”@drawable/yourVector”

PRO TIP: Bulk drawable import in Android Studio. When a lot of assets are being added to an Android project, having to select the .svg files one by one and import them with the “vector asset” option in Android Studio can get pretty tedious. Recent versions of AS, however, have a new resource manager section with a great feature that went by almost unnoticed: bulk import for vector assets. Check it out!

Image for post
Image for post

Making Tuenti

Sharing the daily awesomeness of making Tuenti

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store