Runtime theming of translucent Activities
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!