DeweyReed / Theme

🎨 An Experimental Theme Engine for Android
Apache License 2.0
93 stars 6 forks source link
android android-library android-theme android-theme-library android-ui

[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

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)

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

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