Dynamic theming is a powerful technique for Android apps that need flexible branding. In scenarios like white-label products, enterprise clients, or apps that fetch custom settings from a server, being able to update colors at runtime can save you from maintaining multiple static themes or shipping new builds. In this article, we will explore two practical ways to apply server-defined color schemes in XML-based Android UIs.Dynamic theming is a powerful technique for Android apps that need flexible branding. In scenarios like white-label products, enterprise clients, or apps that fetch custom settings from a server, being able to update colors at runtime can save you from maintaining multiple static themes or shipping new builds. In this article, we will explore two practical ways to apply server-defined color schemes in XML-based Android UIs.

Simple Dynamic Color Schemes in Android Applications

2025/09/02 15:06
5 min read

Dynamic theming is a powerful technique for Android apps that need flexible branding. In scenarios like white-label products, enterprise clients, or apps that fetch custom settings from a server, being able to update colors at runtime can save you from maintaining multiple static themes or shipping new builds.

In this article, we will explore two practical ways to apply server-defined color schemes in XML-based Android UIs:

  • Manual View Theming
  • Using LayoutInflater.Factory2 We will compare the two approaches in terms of scalability, maintainability, and complexity, and also look briefly at how Jetpack Compose makes dynamic theming first-class.

What Are Dynamic Color Schemes?

A dynamic color scheme lets your app load and apply a palette at runtime, based on user preferences, company branding, or remote configuration. Instead of hardcoding styles or toggling between predefined themes, the app adapts its appearance dynamically, keeping the UI consistent with the source of truth on the server.

Example server response:

{   "primary": "#006EAD",   "secondary": "#00C853",   "background": "#FFFFFF",   "surface": "#F5F5F5",   "onPrimary": "#FFFFFF" } 

(A real-world payload would likely include more fields.)

Setup

We’ll define a simple model to represent our theme colors (omitting DTOs and converters for brevity):

data class ThemeColors(     val primary: Int,     val secondary: Int,     val background: Int,     val surface: Int,     val onPrimary: Int ) 

Approach 1: Manual View Theming

How It Works

After inflating a layout, you manually apply colors to each view using findViewById, setBackgroundColor, setTextColor, etc.

Example:

class MainActivity : AppCompatActivity() {      private val themeColors = ThemeColorsRepository.get( /* from server */ )      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_main)          val root = findViewById<ViewGroup>(R.id.rootLayout)         val toolbar = findViewById<Toolbar>(R.id.toolbar)         val titleText = findViewById<TextView>(R.id.titleText)          toolbar.setBackgroundColor(themeColors.primary)         toolbar.setTitleTextColor(themeColors.onPrimary)         root.setBackgroundColor(themeColors.background)         titleText.setTextColor(themeColors.primary)     } } 

✅ Pros

  • Beginner-friendly and easy to debug.
  • Great for prototypes or theming a few views.

❌ Cons

  • Tedious in multi-screen apps.
  • Easy to miss views and lose consistency.
  • Doesn’t scale well.

Approach 2: Using LayoutInflater.Factory2

What Is It?

LayoutInflater.Factory2 is a lesser-known but powerful Android API. It lets you intercept view inflation globally and apply logic (like theming) as views are created.

How It Works

Instead of styling views manually, you “wrap” the inflation process and automatically apply colors to views as they’re inflated from XML.

Example

class ThemingFactory(     private val baseFactory: LayoutInflater.Factory2?,     private val themeColors: ThemeColors ) : LayoutInflater.Factory2 {      override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? {         val view = baseFactory?.onCreateView(parent, name, context, attrs)             ?: LayoutInflater.from(context).createView(parent, name, null, attrs)          applyDynamicTheme(view)         return view      }      override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {         return onCreateView(null, name, context, attrs)     }      private fun applyDynamicTheme(view: View?) {         when (view) {             is TextView -> view.setTextColor(themeColors.primary)             is Button -> {                 view.setBackgroundColor(themeColors.primary)                 view.setTextColor(themeColors.onPrimary)             }             is Toolbar -> {                 view.setBackgroundColor(themeColors.primary)                 view.setTitleTextColor(themeColors.onPrimary)             }         }     } } 

Installation

This must be set before setContentView:

override fun onCreate(savedInstanceState: Bundle?) {     val themeColors = ThemeColors(/* from server */)      val inflater = LayoutInflater.from(this)     val baseFactory = inflater.factory2     LayoutInflaterCompat.setFactory2(inflater, ThemingFactory(baseFactory, themeColors))      super.onCreate(savedInstanceState)     setContentView(R.layout.activity_main) } 

⚠️ Gotcha: With AppCompatActivity, the inflater is overridden internally. If you don’t delegate back to the default AppCompat factory, you’ll lose default styling. A working sample is available here:

  • HomeActivity.kt
  • ThemingFactory.kt

Manual vs Factory2: Feature Comparison

| Feature | Manual View Theming | LayoutInflater.Factory2 Theming | |----|----|----| | Ease of implementation | ✅ Beginner-friendly | ⚠️ Intermediate | | Control per view | ✅ Total | ⚠️ Needs conditionals per view type | | Scalability | ❌ Poor (per view) | ✅ Excellent (global, centralized) | | Boilerplate | ❌ High | ✅ Low | | Reusability | ❌ Limited | ✅ Easy to reuse across screens | | Custom view theming | ❌ Manual only | ✅ Interceptable during inflation | | Dynamic theme switching | ⚠️ Manual re-theming required | ⚠️ Needs re-inflation or restart |

In practice: I applied theming to a large app with dozens of screens in four weeks using LayoutInflater.Factory2. A manual approach would have taken far longer.

Bonus Section: Compose

Jetpack Compose makes it natural to create and apply a custom MaterialTheme dynamically, so you can swap colors at runtime (for example, after fetching them from your server).

Example of implementation:

  1. Define a ThemeColors model (just like in the XML-based version).
  2. Expose it from a ViewModel using StateFlow or LiveData.
  3. Wrap your UI with a MaterialTheme whose colorScheme is derived from ThemeColors.
  4. All Composables that use MaterialTheme.colorScheme will automatically recompose when colors change.

| XML + Factory2 | Jetpack Compose | |----|----| | Manual theming of views (per type) | Global theming via MaterialTheme | | Requires inflating and intercepting views | Native support with recomposition | | Boilerplate-heavy | Minimal, declarative | | Great for legacy codebases | Best for Compose-first apps |

In short, Compose makes dynamic theming a first-class feature, while XML requires custom plumbing (via LayoutInflater.Factory2 or manual updates).

Sample project: Dynamic Theme in Compose

Conclusion

All of the mentioned approaches unlock server-driven dynamic theming, but each fits different needs:

  • Manual theming: Best for small apps, quick prototypes, or theming just a few views.
  • LayoutInflater.Factory2: The way to go for scalable, brand-flexible apps (white-label, multi-client).
  • Jetpack Compose: Dynamic theming is built-in and declarative, ideal for new projects. If you’re working on a legacy XML app, Factory2 will save you huge amounts of time. For new apps, Compose + MaterialTheme is the clear winner.

Further Reading

  • Android Docs: LayoutInflater.Factory2
  • Sample project

\

Market Opportunity
Whiterock Logo
Whiterock Price(WHITE)
$0.00008335
$0.00008335$0.00008335
-0.13%
USD
Whiterock (WHITE) Live Price Chart
Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact crypto.news@mexc.com for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.

You May Also Like

WELIREG® (belzutifan) Plus LENVIMA® (lenvatinib) Reduced the Risk of Disease Progression or Death by 30% Compared to Cabozantinib in Certain Previously Treated Patients With Advanced Renal Cell Carcinoma (RCC)

WELIREG® (belzutifan) Plus LENVIMA® (lenvatinib) Reduced the Risk of Disease Progression or Death by 30% Compared to Cabozantinib in Certain Previously Treated Patients With Advanced Renal Cell Carcinoma (RCC)

This is the first positive Phase 3 trial of a HIF-2 alpha inhibitor in combination with a multi-targeted tyrosine kinase inhibitor, the first for patients with
Share
AI Journal2026/02/28 23:15
Why Bitcoin traders have to price tariffs like surprise rate hikes while waiting on social media posts for the next $175B trigger

Why Bitcoin traders have to price tariffs like surprise rate hikes while waiting on social media posts for the next $175B trigger

The US Supreme Court struck down President Donald Trump’s emergency tariffs under IEEPA on Feb. 20, and markets immediately inherited a large cash flow question
Share
CryptoSlate2026/02/28 22:50
Fed forecasts only one rate cut in 2026, a more conservative outlook than expected

Fed forecasts only one rate cut in 2026, a more conservative outlook than expected

The post Fed forecasts only one rate cut in 2026, a more conservative outlook than expected appeared on BitcoinEthereumNews.com. Federal Reserve Chairman Jerome Powell talks to reporters following the regular Federal Open Market Committee meetings at the Fed on July 30, 2025 in Washington, DC. Chip Somodevilla | Getty Images The Federal Reserve is projecting only one rate cut in 2026, fewer than expected, according to its median projection. The central bank’s so-called dot plot, which shows 19 individual members’ expectations anonymously, indicated a median estimate of 3.4% for the federal funds rate at the end of 2026. That compares to a median estimate of 3.6% for the end of this year following two expected cuts on top of Wednesday’s reduction. A single quarter-point reduction next year is significantly more conservative than current market pricing. Traders are currently pricing in at two to three more rate cuts next year, according to the CME Group’s FedWatch tool, updated shortly after the decision. The gauge uses prices on 30-day fed funds futures contracts to determine market-implied odds for rate moves. Here are the Fed’s latest targets from 19 FOMC members, both voters and nonvoters: Zoom In IconArrows pointing outwards The forecasts, however, showed a large difference of opinion with two voting members seeing as many as four cuts. Three officials penciled in three rate reductions next year. “Next year’s dot plot is a mosaic of different perspectives and is an accurate reflection of a confusing economic outlook, muddied by labor supply shifts, data measurement concerns, and government policy upheaval and uncertainty,” said Seema Shah, chief global strategist at Principal Asset Management. The central bank has two policy meetings left for the year, one in October and one in December. Economic projections from the Fed saw slightly faster economic growth in 2026 than was projected in June, while the outlook for inflation was updated modestly higher for next year. There’s a lot of uncertainty…
Share
BitcoinEthereumNews2025/09/18 02:59