Customising Android App UI with Themes
Article Summary
Maxim Kostenko from Revolut reveals how they built one of the most customizable Android apps on the market. Their approach goes far beyond basic dark mode—and it required reverse-engineering Android's own framework.
Most Android apps stop at light/dark themes, but Revolut offers users complete control: system-wide dynamic colors, custom color palettes, and real-time theme switching. This deep dive explains the technical implementation behind each personalization layer, including the challenges of runtime theme changes without official Android APIs.
Key Takeaways
- Dynamic colors work via theme overlays, not full Material3 migration
- Runtime theme switching requires recreating all activities manually
- Custom ColorThemesController mimics private AppCompatDelegate behavior
- Theme overlays apply like HashMap keys, replacing specific color tokens
- Cross-platform custom themes solve iOS/Android personalization parity
Revolut achieved maximum Android UI personalization by combining dynamic colors, custom theme overlays, and a custom controller that forces activity recreation—techniques that work without migrating to Material3.
About This Article
Maxim Kostenko's team at Revolut needed to switch themes at runtime across all active activities. Android's private AppCompatDelegate API only handles light and dark mode, so they needed a different approach.
They created ColorThemesController using ActivityLifecycleCallbacks to keep track of activity references in a static set. The controller loops through each activity and calls applyDayNight to force them to recreate, which is how Android handles dynamic color and custom theme overlays internally.
Users can now switch between default, dynamic, and custom Orange themes instantly at runtime. Material Design naming conventions for color tokens like colorPrimary and colorSecondary stay consistent across all screens.