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

f058fe8 Β· Oct 10, 2024
Feb 6, 2021
Jul 4, 2021
Jul 4, 2021
May 14, 2020
Jul 4, 2021
Aug 18, 2019
Nov 11, 2018
Oct 10, 2024
Jul 4, 2021
Jul 4, 2021
Oct 14, 2018
Jun 16, 2020
Oct 14, 2018
Jan 4, 2020

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 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