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

\

Clause de non-responsabilité : les articles republiés sur ce site proviennent de plateformes publiques et sont fournis à titre informatif uniquement. Ils ne reflètent pas nécessairement les opinions de MEXC. Tous les droits restent la propriété des auteurs d'origine. Si vous estimez qu'un contenu porte atteinte aux droits d'un tiers, veuillez contacter service@support.mexc.com pour demander sa suppression. MEXC ne garantit ni l'exactitude, ni l'exhaustivité, ni l'actualité des contenus, et décline toute responsabilité quant aux actions entreprises sur la base des informations fournies. Ces contenus ne constituent pas des conseils financiers, juridiques ou professionnels, et ne doivent pas être interprétés comme une recommandation ou une approbation de la part de MEXC.
Partager des idées

Vous aimerez peut-être aussi

Ethereum Closes Holesky Doors: Will Hoodi Deliver?

Ethereum Closes Holesky Doors: Will Hoodi Deliver?

The Ethereum Holesky shutdown has officially been confirmed, marking the closure of the network’s largest testnet. The Ethereum Foundation announced that Holesky will sunset following the Fusaka upgrade, paving the way for developers to migrate to the newer Hoodi testnet.  Timeline of Closure and Holesky’s Role in Ethereum Testing According to the foundation, the Ethereum Holesky shutdown will occur two weeks after the Fusaka upgrade finalizes on Holesky. Although an exact date has not yet been determined, the closure is expected to happen in the second half of September, well ahead of Fusaka’s mainnet launch scheduled for November. After this point, Holesky will no longer receive support from infrastructure, client, or testing teams. Launched in September 2023, Holesky was built to serve as Ethereum’s largest validator and staking testnet. It played a central role in allowing thousands of validators to test major upgrades, including the Dencun and Pectra forks. By providing a realistic environment for validator lifecycle testing, Holesky ensured that critical features were trialed before being deployed on the mainnet. The Ethereum Holesky shutdown now concludes this two-year experiment. Source: X Technical Challenges That Led to Closure While Holesky delivered important contributions, its limitations became clear in early 2025. The network suffered extensive inactivity leaks that created months-long validator exit queues. These delays made it difficult to test validator operations effectively, frustrating developers who needed quick feedback.  Also read: Ethereum’s Holesky Testnet Restores Finality, Pectra Testing Resumes Although the network recovered, confidence had eroded. The Ethereum Holesky shutdown was therefore a practical solution to prevent further inefficiencies and redirect resources to more reliable testnets. Hoodi Testnet as the New Successor To address Holesky’s shortcomings, the Ethereum Foundation launched the Hoodi testnet in March 2025. Designed as a clean-slate environment, Hoodi eliminates prolonged validator queues and supports fast development cycles.  It already runs the Pectra update and will also support the upcoming Fusaka fork. The Ethereum Holesky shutdown effectively transfers staking and validator testing responsibilities to Hoodi, which is now positioned as the primary network for these operations. Role of Sepolia and Ephemery in the Ecosystem The transition does not leave developers without options. Sepolia continues to serve as the main testnet for decentralized applications and smart contract testing. Meanwhile, Ephemery provides rapid-reset validator cycles every 28 days, offering flexibility for short-term experiments.  Importance of the Fusaka Upgrade Central to Ethereum’s upcoming roadmap is the Fusaka upgrade, scheduled for November 2025. Fusaka introduces 11 Ethereum Improvement Proposals designed to enhance rollup efficiency, distribute data workloads more evenly, and reduce transaction costs.  By simplifying node operations, Fusaka aims to make the network more decentralized and scalable. The Ethereum Holesky shutdown ensures that developers’ efforts are concentrated on testnets capable of fully supporting Fusaka’s requirements. Looking further ahead, the Ethereum community is preparing for the Glamsterdam upgrade, expected in 2026. Proposed under EIP-7782, Glamsterdam seeks to halve block times to six seconds and separate block validation from execution, thereby enabling more efficient zero-knowledge proof generation.  Market Implications and Community Response The Ethereum Holesky shutdown has been met with understanding from both the community and the market. While some developers expressed nostalgia for Holesky’s role, most acknowledge that Hoodi offers a stronger, faster, and more reliable testing environment.  The broader market has reacted positively to Ethereum’s steady pace of upgrades. ETH prices have risen more than 200% since April as institutions increase their exposure to the asset. Conclusion The Ethereum Holesky shutdown represents a significant turning point for Ethereum’s testing ecosystem. Holesky served its purpose by enabling large-scale validator testing and major upgrade trials, but its technical flaws made long-term use unsustainable.  By shifting focus to Hoodi, alongside Sepolia and Ephemery, Ethereum is ensuring that its testnet landscape is both reliable and efficient. This transition highlights the foundation’s long-standing commitment to building a network that balances scalability, decentralization, and user experience. Also read: Vitalik Just Proposed a Radical Shift for Ethereum’s Future Summary The Ethereum Holesky shutdown ends the network’s largest validator testnet. It closes after two years of service due to technical challenges. Developers will now migrate to Hoodi, a faster and more reliable successor. Hoodi is built to support upcoming upgrades like Fusaka.  Sepolia and Ephemery will remain active for dapp and short-cycle testing. The move streamlines Ethereum’s testnet ecosystem. It reinforces the network’s focus on scalability, decentralization, and user experience. It also prepares Ethereum for future upgrades. Appendix: Glossary of Key Terms Ethereum Holesky Shutdown – Planned closure of Ethereum’s largest validator testnet. Hoodi Testnet – A new environment replacing Holesky for validator testing. Fusaka Upgrade – Ethereum’s upcoming fork aimed at scaling rollups. Sepolia Testnet – Primary testing ground for dapps and smart contracts. Ephemery Testnet – Short-cycle testnet with 28-day validator resets. Pectra Update – A recent protocol upgrade trialed on testnets. Dencun Upgrade – A major past Ethereum upgrade supported by Holesky. FAQs for Ethereum Holesky shutdown 1-Why is the Ethereum Holesky shutdown happening? The shutdown addresses persistent technical issues, including validator inactivity leaks and impractical exit queues, which made Holesky less efficient for testing. 2- What replaces Holesky after the shutdown? Hoodi testnet now serves as the main environment for validator and staking provider testing, while Sepolia remains the primary dapp testnet. 3- When will the Ethereum Holesky shutdown occur? It will take place two weeks after the Fusaka upgrade finalizes on Holesky, expected in September 2025. 4- Will the Ethereum Holesky shutdown affect dapp developers? No. Developers testing smart contracts should continue using Sepolia as recommended by the Ethereum Foundation. Read More: Ethereum Closes Holesky Doors: Will Hoodi Deliver?">Ethereum Closes Holesky Doors: Will Hoodi Deliver?
Partager
Coinstats2025/09/03 01:00
Partager