Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set theme color dynamically

I am using themes (dynamically) in my android app, like this:

my_layout.xml (extract):

<TextView
    android:id="@+id/myItem"
    style="?my_item_style" />

attrs.xml (extract):

<attr name="my_item_style" format="reference" />

themes.xml (extract):

<style name="MainTheme.Blue">
      <item name="my_item_style">@style/my_item_style_blue</item>
</style>

<style name="MainTheme.Green">
      <item name="my_item_style">@style/my_item_style_green<item>
</style>

styles.xml (extract):

<style name="my_item_style_blue">
      <item name="android:textColor">@color/my_blue</item>
</style>

<style name="my_item_style_green">
      <item name="android:textColor">@color/my_blue</item>
</style>

So, as you can see, I am setting themes dynamically. I am using this class:

public class ThemeUtils {

  private static int sTheme;
  public final static int THEME_BLUE = 1;
  public final static int THEME_GREEN = 2;

  public static void changeToTheme(MainActivity activity, int theme) {
      sTheme = theme;
      activity.startActivity(new Intent(activity, MyActivity.class));
  }

  public static void onActivityCreateSetTheme(Activity activity)
  {
      switch (sTheme)
      {
          default:
          case THEME_DEFAULT:
          case THEME_BLUE:
              activity.setTheme(R.style.MainTheme_Blue);
              break;
          case THEME_GREEN:
              activity.setTheme(R.style.MainTheme_Green);
              break;
      }
  }

}

What I want to know, is there a way how to do this (change theme color) in code? For example, I have following code (extract):

((TextView) findViewById(R.id.myItem)).setTextColor(R.color.blue);

It can be done by some helper method, which would use switch command for available themes and return correct color for a theme. But I would like to know if there is some better, nicer and faster way.

Thanks!

like image 215
Tom11 Avatar asked Mar 21 '17 09:03

Tom11


People also ask

What is Google dynamic colour?

Recommendations from Google Chrome designers Create a unified design system: Material 3 and dynamic color gives the opportunity to reconcile your app's themes. For Chrome that meant reconciling their light and dark theme and removing fragmentation based on elevation.


3 Answers

I have finally done it using following method:

public static int getColor(String colorName) {
    Context ctx = getContext();
    switch (sTheme) {
        default:
        case THEME_DEFAULT:
            return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
        case THEME_BLUE:
            return ctx.getResources().getIdentifier("BLUE_" + colorName, "color", ctx.getPackageName());
        case THEME_GREEN:
            return ctx.getResources().getIdentifier("GREEN_" + colorName, "color", ctx.getPackageName());
    }
}

This returns color according to my theme (I used prefixes).

like image 191
Tom11 Avatar answered Oct 19 '22 21:10

Tom11


If I understand corectly you're looking for a way to

  1. extract a style from a theme,
  2. extract a value (text color) from said style.

Let's get to it.

// Extract ?my_item_style from a context/activity.
final TypedArray a = context.obtainStyledAttributes(new int[] { R.attr.my_item_style });
@StyleRes final int styleResId = a.getResourceId(0, 0);
a.recycle();

// Extract values from ?my_item_style.
final TypedArray b = context.obtainStyledAttributes(styleResId, new int[] { android.R.attr.textColor });
final ColorStateList textColors = b.getColorStateList(0);
b.recycle();

// Apply extracted values.
if (textColors != null) {
    textView.setTextColor(textColors);
}

A couple of notes:

  1. TypedArray does not support getting support vector drawables and theme references in color state lists on older API levels. If you're willing to use AppCompat internal API you may want to try TintTypedArray.
  2. Allocating int[] all the time is costly, make it a static final.
  3. If you want to resolve multiple attributes at once the array of attributes has to be sorted! Else it crashes sometimes. <declare-styleable> generates such array and corresponding indices for you.
like image 31
Eugen Pechanec Avatar answered Oct 19 '22 20:10

Eugen Pechanec


Have you check this MultipleThemeMaterialDesign demo?

enter image description here

SettingActivity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    Preferences.applyTheme(this);
    getDelegate().installViewFactory();
    getDelegate().onCreate(savedInstanceState);
    super.onCreate(savedInstanceState);
    setToolbar();
    addPreferencesFromResource(R.xml.preferences);
    Preferences.sync(getPreferenceManager());
    mListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            Preferences.sync(getPreferenceManager(), key);
            if (key.equals(getString(R.string.pref_theme))) {
                finish();
                final Intent intent = IntentCompat.makeMainActivity(new ComponentName(
                        SettingsActivity.this, MainActivity.class));
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(intent);
            }
        }
    };
}

See full example for demo.

like image 28
Pratik Butani Avatar answered Oct 19 '22 19:10

Pratik Butani