Theme

Project Url: DeweyReed/Theme
Introduction: 🎨 An Experimental Theme Engine for Android
More: Author   ReportBugs   
Tags:

Android CI API Releases

image

Theme is an experimental theme engine for Android by retinting views after their creation.

This library is inspired by aesthetic and Cyanea.

WARNING

  • Theme is a companion of material-components-android, so it requires you to adopt material-components-android in your project.
  • Currently, Theme only supports material-components-android 1.4.0. Any other version doesn't work.
  • Because the implementation is fragile, think twice, and do some investigation before using this library.
  • Jetpack Compose supports theming programmatically and is a better alternative(in the future).

Sample App

Sample APK from Release.

Usage

  1. Install dependency:

    1. Add the JitPack repository to your build file

       allprojects {
           repositories {
               ...
               maven { url 'https://jitpack.io' }
           }
       }
      
    2. Add the dependency

      Releases

       dependencies {  
           implementation 'com.github.DeweyReed:Theme:0.4.0' // for material-components-android 1.4.0
       }
      
  2. Define six theme colors:

     <resources>
         <color name="colorPrimary">#008577</color>
         <color name="colorPrimaryVariant">#00574B</color>
         <color name="colorOnPrimary">#FFFFFF</color>
         <color name="colorSecondary">#D81B60</color>
         <color name="colorSecondaryVariant">#A00037</color>
         <color name="colorOnSecondary">#FFFFFF</color>
     </resources>
    
    • The color resources name must be identical to the names above.
    • Color values must be formatted as #RRGGBB. Color references won't work because of how TypedArray.getResourceId works).
  3. Add an attribute to your root theme:

     <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
         ...
         <!-- Add this line -->
         <item name="viewInflaterClass">xyz.aprildown.theme.ThemeViewInflater</item>
     </style>
    
  4. In your Application:

     Theme.init(
         context = this,
         themeRes = R.style.AppTheme
     ) {
         // Optional. Provide initial colors here.
         // The usage is same as the code below.
     }
    
  5. Change colors:

     Theme.edit(this) {
         colorPrimaryRes = R.color.md_amber_500
         colorPrimaryVariantRes = R.color.md_amber_800
         colorOnPrimary = on(colorPrimary)
         colorSecondaryRes = R.color.md_blue_500
         colorSecondaryVariantRes = R.color.md_blue_800
         colorOnSecondary = on(colorSecondary)
         colorStatusBar = colorPrimaryVariant
     }
    
    • Variables ending with Res expect a ColorRes. Other variables expect a ColorInt.
    • After editing, you have to recreate activities in the back stack manually.
  6. [Optional] Use colors at runtime.

     Theme.get().colorPrimary
    

More Settings

Tint Status Bar and Navigation Bar

Theme.tintSystemUi(activity)
  • Put it in activity's onCreate, but if you're using DrawerLayout, put it after DrawerLayout is inflated(usually it's after setContentView).

Disable Theme

This's useful when you show a MaterialDatePicker because Theme messes up its colors.

button.setOnClickListener {
    Theme.get().enabled = false
    MaterialDatePicker.Builder.datePicker()
        .build()
        .apply {
            addOnDismissListener {
                Theme.get().enabled = true
            }
        }
        .show(childFragmentManager, null)
}

Support Custom Views

  1. Create a ThemeInflationDelegate like AppComponentsDelegate.
  2. Add it after Theme's initialization:

     Theme.init(...)
     Theme.installDelegates(AppComponentsDelegate())
    

Limitation

  • Style Toolbar according to the docs, or the tint doesn't work.
  • Theme doesn't use any reflection, so it's hard to tint widgets like TimePicker.

How Theme Works

material-components-android makes setting attributes programmatically very easy. ThemeViewInflater extends MaterialComponentsViewInflater and does all retint work. Classes named ***Tint resolves color attributes from AttributeSet and applies new color.

License

Apache License 2.0

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools