0
votes

I'm trying to implement a dark theme to my app. The user can easily change between normal and dark in an options menu – which works fine. But when the theme is changed at runtime, only the text color changes and I don't know why.

My dark theme in styles.xml:

<style name="Dark" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/dark_background</item>
    <item name="colorPrimaryDark">@color/dark_top</item>
    <item name="colorAccent">@color/dark_button</item>
    <item name="colorButtonNormal">@color/dark_button</item>
    <item name="android:colorBackground">@color/dark_background</item>
    <item name="android:itemBackground">@color/dark_background</item>
    <item name="android:textColor">@color/white</item>
    <item name="android:textColorHint">#EAEAEA</item>
    <item name="android:textColorPrimary">@color/white</item>
    <item name="android:textColorSecondary">@color/white</item>
    <item name="android:textColorTertiary">@color/white</item>
</style>

My way of setting the style:

setTheme(R.style.Dark);

Before changing theme: before

After changing theme: after

I don't really know why. Is it because of the NavigationView?

1
Where do you use setTheme(R.style.Dark)?Sinan Ceylan
currently after setContentView because otherwise the app crashesTheBC97
You should call it before setContentView() that's why your views don't change color. Please, send your crashlog when you call it before setContentView().Sinan Ceylan

1 Answers

0
votes

Make sure you are calling setTheme() before setContentView() or inflating a view. According to the documentation you must use setTheme() before any views are instantiated in the Context. Use recreate() to create a new instance of your activity so you can apply the changed theme in the onCreate() method.

You can find several examples of theme switching if you search around a little bit. This is a link to one such example: https://gist.github.com/alphamu/f2469c28e17b24114fe5

I use PreferenceManager to store settings like this for easy access if I have more than one activity that will need to use the setting. Unless you already have a better way to store your users' theme choice, I would suggest something like the following examples.

Example MyAppPreferences class:

public class MyAppPreferences {

    private static SharedPreferences getPrefs(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context);
    }

    public static int getThemeId(Context context, int defaultThemeId) {
        return getPrefs(context).getInt("CurrentThemeId", defaultThemeId);
    }
    public static void setThemeId(Context context, int value) {
        getPrefs(context).edit().putInt("CurrentThemeId", value).commit();
    }

}

Example Activity class using the MyAppPreferences class:

public class MyActivity extends AppCompatActivity implements OnClickListener {

    private Button btnDark;
    private Button btnLight;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);            
        // Set the theme
        // If there is nothing set, the light theme will be used by default
        setTheme(MyAppPreferences.getThemeId(this, R.style.Light));
        setContentView(R.layout.myLayout);

        btnDark = (Button) this.findViewById(R.id.viewbtnDark);
        btnDark.setOnClickListener(this);

        btnLight = (Button) this.findViewById(R.id.viewbtnLight);
        btnLight.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // 1. Set the theme preference
        // 2. Recreate the activity to "apply" the theme
        if (v.equals(btnDark)) {
            MyAppPreferences.setThemeId(this, R.style.Dark);
            this.recreate();
        } else if (v.equals(btnLight)) {
            MyAppPreferences.setThemeId(this, R.style.Light);
            this.recreate();
        }
    }

}

Your example theme does not show the windowActionBar or windowNoTitle settings so if you happen to be using a default theme and you do not set these options the same way in your dark theme, you may still encounter crashes. Check Logcat for an error like this: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor..

Example Dark theme

<style name="Dark" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/dark_background</item>
    <item name="colorPrimaryDark">@color/dark_top</item>
    <item name="colorAccent">@color/dark_button</item>
    <item name="colorButtonNormal">@color/dark_button</item>
    <item name="android:colorBackground">@color/dark_background</item>
    <item name="android:itemBackground">@color/dark_background</item>
    <item name="android:textColor">@color/white</item>
    <item name="android:textColorHint">#EAEAEA</item>
    <item name="android:textColorPrimary">@color/white</item>
    <item name="android:textColorSecondary">@color/white</item>
    <item name="android:textColorTertiary">@color/white</item>
</style>