Search code examples
androidandroid-layoutandroid-themeandroid-styles

How to Switch theme for an activity


So here is the situation:

  1. I have DogActivity and FavoritesActivity. DogActivity is just a ListView. When you click on a Dog in the list, it takes you to FavoritesActivity.
  2. I want to have a number of themes ready to go. They don’t need to be dynamically generated. They can already exist in XML form.
  3. Depending on which dog the user selects from the list, I want to have the FavoritesActivity shown in one of my pre-existing themes.

I hear talks about ContextWrapper, but I am not sure how to apply it. Any thoughts on how I may accomplish this?

Details:

Here is the usual single theme:

for v21/styles.xml

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:colorControlHighlight">@color/colorAccentLight</item>
        <item name="android:colorControlNormal">@color/colorAccent</item>
        <item name="android:itemTextAppearance">@style/AppTheme.itemTextStyle</item>
        <item name="popupMenuStyle">@style/PopupMenu.MyAppTheme</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:colorControlHighlight">@color/colorAccentLight</item>
    </style>

    <style name="AppTheme.itemTextStyle" parent="@android:style/TextAppearance.Widget.IconMenu.Item">
        <item name="android:textColor">@color/colorPrimary</item>
    </style>
</resources>

for styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

Want I want to do:

Essentially I just want to change the colorPrimary, colorPrimaryDark and colorAccent on the fly and have all the styles and themes and XML layouts that use them to change. So if I can change those colors before I launch FavoritesActivity then that would solve my problems.


Solution

  • You can just send the dog type as an Intent extra, and then use the setTheme() method to set the appropriate Theme.

    For this example, suppose you just have two Themes:

    <style name="AppThemeOne" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    
    <style name="AppThemeTwo" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimaryCustom</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDarkCustom</item>
        <item name="colorAccent">@color/colorAccentCustom</item>
    </style>
    

    Then, in DogActivity, set an Intent Extra to the Dog type the user selected from the ListView:

    Intent intent = new Intent(DogActivity.this, FavoritesActivity.class);
    intent.putExtra("dog_type", "terrier");
    startActivity(intent);
    

    Then, in FavoritesActivity, load the correct Theme:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
        String dogType = getIntent().getStringExtra("dog_type");
        if (dogType.equals("terrier")) {
            setTheme(R.style.AppThemeOne);
        } else {
            setTheme(R.style.AppThemeTwo);
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.favorites_layout);
        //.....
     }