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

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

\

면책 조항: 본 사이트에 재게시된 글들은 공개 플랫폼에서 가져온 것으로 정보 제공 목적으로만 제공됩니다. 이는 반드시 MEXC의 견해를 반영하는 것은 아닙니다. 모든 권리는 원저자에게 있습니다. 제3자의 권리를 침해하는 콘텐츠가 있다고 판단될 경우, service@support.mexc.com으로 연락하여 삭제 요청을 해주시기 바랍니다. MEXC는 콘텐츠의 정확성, 완전성 또는 시의적절성에 대해 어떠한 보증도 하지 않으며, 제공된 정보에 기반하여 취해진 어떠한 조치에 대해서도 책임을 지지 않습니다. 본 콘텐츠는 금융, 법률 또는 기타 전문적인 조언을 구성하지 않으며, MEXC의 추천이나 보증으로 간주되어서는 안 됩니다.

추천 콘텐츠

New Viral Presale on XRPL: DeXRP Surpassed $6.4 Million

New Viral Presale on XRPL: DeXRP Surpassed $6.4 Million

The post New Viral Presale on XRPL: DeXRP Surpassed $6.4 Million  appeared on BitcoinEthereumNews.com. One of the most talked-about ecosystems in the cryptocurrency space is the XRP Ledger (XRPL), and DeXRP, the first Presale on XRPL, recently made headlines for its growth story. Attracting over 9,300 investors globally, the project has now raised over $6.4 million and is rapidly emerging as one of the most viral cryptocurrency launches of 2025. By integrating AMM and Order Book trading with a cutting-edge LP system and an open voting process for holders, DeXRP hopes to establish itself as the preferred trading destination for the XRPL community. What is DeXRP?  As the first decentralized exchange (DEX) based on XRPL, DeXRP is taking center stage as XRP continues to solidify its place in the global market. Massive expectation has been generated by the combination of DeXRP’s ambition for an advanced trading platform and XRPL’s established infrastructure, which is renowned for its quick transactions, cheap fees, and institutional-ready capabilities. In contrast to a lot of speculative presales, DeXRP’s development shows both institutional interest and community-driven momentum. Its early achievement of the $6.4 million milestone demonstrates how rapidly investors are realizing its potential. DeXRP Presale Success More than 9,300 distinct wallets have already joined the DeXRP presale, indicating a high level of interest from around the world. A crucial aspect is highlighted by the volume and variety of participation: DeXRP is not merely a niche project; rather, it is emerging as a major force in the XRPL ecosystem. DeXRP’s recent collaborations with WOW Earn and Micro3, as well as its sponsorship of the WOW Summit in Hong Kong, are also contributing factors to this uptick in investor confidence. These actions are blatant attempts to increase the company’s awareness among institutional players and crypto-native groups. The Forbes article summed it up: DeXRP is embedding credibility where others chase hype, marking it as…
공유하기
BitcoinEthereumNews2025/09/18 20:14