Runtime theming of translucent Activities

George Venios
pxHouse
Published in
2 min readJan 29, 2018

The curious case of windowIsTranslucent

Nowadays, it’s common to see apps allowing the user to change their look. A common way of implementing this is by passing the user’s theme of choice to setTheme(). For most cases, you don’t need to set a theme for the Activity in the AndroidManifest as any operation involving it will happen after the setTheme() call.

But what if you need a themed activity to be translucent? Android seems to ignore the windowIsTranlucent=true flag on themes passed to setTheme() and keeps our Window opaque. Trying to set a translucent Theme in AndroidManifest does retain the flag, but we can’t know which variant the user has picked at compile time and we’d lose the benefit of any custom styling and/or attributes.

The solution

The solution to retaining window translucency with custom styling comes by using a simple, if somewhat hidden, trick.

1. First, we need to set a translucent theme for the Activity on the manifest — @android:style/Theme.Translucent for example. Any translucent theme would suffice since we’ll be overwriting the in-memory copy that will be used for inflations.

2. Then, instead of directly setting our theme by calling setTheme(R.style.MyOwnTranslucentTheme) (which will disable the translucency no matter the flag’s value), we need to update the Activity’s theme with the attributes and values of the actual theme we intended to use. Just call getTheme().applyStyle(R.style.MyOwnTranslucentTheme, true) to fill the copy of Theme.Translucent with the attributes from MyOwnTranslucentTheme.

That was it! You can now have the user select a theme and keep using it on your translucent Activities!

One more thing…

Worth noting is that this technique can’t be used to enable window translucency at runtime. Android seems to only enable it when it is set on the theme used in the AndroidManifest and there are no calls to setTheme() in the activity code. Trying to set the flag by using the applyStyle() trick bears pretty inconsistent results, as illustrated by this painstakingly crafted ASCII table:

╔═══════════════════╦════════════════════╦═════════════════════════╗║ Initial/XML Theme ║  Overriding theme  ║         Result          ║
╠═══════════════════╬════════════════════╬═════════════════════════╣
║ True ║ False ║ Becomes opaque ║
║ False ║ True ║ Remains opaque ║
║ True ║ True ║ Remains translucent ║
║ False ║ False ║ Remains opaque ║
╚═══════════════════╩════════════════════╩═════════════════════════╝

The first two columns are values of the windowIsTranslucent theme attribute defined on the respective themes.

Want to see this trick used in production? Check out Dir, an open source file manager app for Android.

We’re always looking for contributors — visit the project’s Github page for more info!

--

--