Skip to content

🎨 An Experimental Theme Engine for Android

License

Notifications You must be signed in to change notification settings

DeweyReed/Theme

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

[Experimental] Theme

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 supports material-components-android 1.1.0, 1.2.x, 1.3.0 and 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 'xyz.aprildown:Theme:0.4.0' // for material-components-android 1.4.0
          // implementation 'xyz.aprildown:Theme:0.3.1' // for material-components-android 1.3.0
          // implementation 'xyz.aprildown:Theme:0.2.0' // for material-components-android 1.2.x
          // implementation 'xyz.aprildown:Theme:0.1.4' // for material-components-android 1.1.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