5

I'd like to make a SettingsActivity to let the user personalize the appearence of the app. In this activity the user can choose to keep the app in a "light theme" (that means for example white backgrounds with black texts) or a "dark theme", the opposite colours of light theme to favour the night use.

How could it be done?

I was thinking about creating different layouts in xml for each theme.

EDITS

The images below are examples of SettingsActivity, I'd like to change the appearence for the whole app, not single activity.

enter image description here

enter image description here

enter image description here

enter image description here

Pier
  • 794
  • 1
  • 12
  • 27

4 Answers4

5

This is how I've done it for my app. I'm sure my approach can help.

Set up your Light and Dark themes in styles.xml like this:

     <!-- Use this theme in Manifest by default -->
    <style name="MyLightTheme" parent="Base.AppTheme.Light"></style>
    
    <!-- Base light theme containing all styles -->
    <style name="Base.AppTheme.Light" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        ... Other styles
    </style>

    <!-- Use this to switch to Dark theme -->
    <style name="MyDarkTheme" parent="Base.AppTheme.Dark"></style>

    <!-- Base dark theme containing all styles -->
    <style name="Base.AppTheme.Dark" parent="Theme.AppCompat">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        ... Other styles
    </style>

Since you're controlling Theme change via a preference, register a preference change listener in your PreferenceFragment.

PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this);

Implement onSharedPreferenceChanged():

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

        if (key.equals(getString(R.string.pref_key_nighttheme))) {

            if (sharedPreferences.getBoolean(getString(R.string.pref_key_nighttheme), false)) {
                //  Night theme enabled

                getActivity().setTheme(R.style.MyDarkTheme);  
                       getActivity().getApplication().setTheme(R.style.MyDarkTheme);
               darkTheme = true;

            } else {
                getActivity().setTheme(R.style.MyLightTheme);
                getActivity().getApplication().setTheme(R.style.MyLightTheme);
               darkTheme = false;
            }

            getActivity().recreate(); // This is important. It allows the theme change to take effect.
        } 
    }

Be sure to recreate your MainActivity in onResume() if Back Navigation leads to MainActivity.


Additionally, you must check for the current theme in EVERY Activity, BEFORE super() is called in onCreate().

  isThemeDark = setDarkTheme(this);

setDarkTheme() is a helper I've created which checks the current Theme via SharedPreference. It checks if a Theme change is necessary or not.

    public static boolean setDarkTheme(Context context) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

    boolean isDarkTheme = prefs.getBoolean(context.getString(R.string.pref_key_nighttheme), false);
    context.setTheme(SettingsActivity.darkTheme ? R.style.MyDarkTheme : R.style.MyLightTheme);

    return isDarkTheme;
}

Here's how Night mode works in my app Newslet:

enter image description here

UPDATE: Android now officially supports Night Mode via its AppCompat DayNight Theme. Here's a tutorial on the same.

Suleiman19
  • 742
  • 1
  • 7
  • 21
3

You can create your own theme and then when the user want to change the them add this code to your activity you can choose any theme you want not just Holo.

getApplication().setTheme(Theme.Holo)

RadiBarq
  • 31
  • 3
  • But how could I change every layout of the app simply from a _CheckBox_ in _SettingsActivity_, all in a single style? I mean, every view I have has its own "personalizations" – Pier Jul 31 '16 at 01:38
  • you can create your own style and change the style of every activity from the manifest file, if don't know how to create your own style I will tell you how. – RadiBarq Jul 31 '16 at 23:02
  • Maybe what I'm asking is not clear... I don't want to change a single style per activity from the manifest. I want a SettingsActivity where, among other personalizations, I can switch between multple themes (green, blue, black, white, red) for the whole app, like you can see in the images in the edits above. Every layout has its own views that differ each other so it is difficult, in my opinion, making all those changes in a style – Pier Aug 01 '16 at 13:22
  • I got it, you can do it by adding public static variable to your setting activity, this variable you can put inside it all the possible themes that you want to change, when you change the theme change the string inside the variable, then add the upper code that I mentioned earlier to every activity you have inside the onCreate method but change (Theme.Holo to your Public Variable). I hope this is helpful. – RadiBarq Aug 01 '16 at 15:50
  • It is helpful but I need a more detailed answer because as a newbie in android programmation I've never worked with PreferenceActvitiy – Pier Aug 01 '16 at 16:19
  • I think you don't have to know much programming, just declare a variable for example: public static String THEME = ""; then you can access it from other classes like this (settingActivity.Theme), I think you should learn some java this will be very helpful. If you want, give me your project file I will edit it four you and return it back. – RadiBarq Aug 01 '16 at 23:06
3

Maybe this answer can help you with this problem https://stackoverflow.com/a/4673209/4858673

public class BaseActivity extends Activity {

    protected void onCreate(Bundle state) {
        super.onCreate(state);
        String theme = PreferenceManager.getDefaultSharedPreferences(this).getString("theme", "black");
        setTheme(getTheme(theme);
    }

    private int getTheme(String theme) {
        if (theme.equals("black") return R.style.ThemeBlack;
        if (theme.equals("white") return R.style.ThemeWhite;
        ...
        return android.R.style.Theme; // stub
    }
}

And extend all your activities from this BaseActivity. If you want to use PreferenceActivity or PreferenceFragment, put this code into your implementation, so you can extend only one class - Activity (AppCompatActivity) or PreferenceActivity

P.S. R.style.ThemeBlack is your theme settings in styles.xml

<style name="ThemeBlack" parent="android:Theme.Holo">
</style>
Community
  • 1
  • 1
2
  1. First you need to create some well defined themes in xml-styles.

    <style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/primaryColorAmber</item>
        <item name="colorPrimaryDark">@color/primaryDarkColorAmber</item>
        <item name="colorAccent">@color/secondaryColorAmber</item>
    </style>
    
    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
    
    <style name="AppTheme.RED" parent="AppTheme.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/primaryColorRed</item>
        <item name="colorPrimaryDark">@color/primaryDarkColorRed</item>
        <item name="colorAccent">@color/secondaryColorRed</item>
    </style>
    
    <style name="AppTheme.PINK" parent="AppTheme.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/primaryColorPink</item>
        <item name="colorPrimaryDark">@color/primaryDarkColorPink</item>
        <item name="colorAccent">@color/secondaryColorPink</item>
    </style>
    
  2. To change theme at runtime use following code in your base activity onCreate() method and just before setContentView().

    // To change theme just put your theme id.

    int theme = getThemeFromPreferences(); // R.style.AppTheme_RED
    setTheme(theme);
    
  3. To change theme of your setting/preference activity (from where you are changing theme) you need to recreate that activity by calling following method of that activity.

    //store your theme id in preference

    saveThemeInPreferences(R.style.AppTheme_RED);
    //recreate this activity to see changes
    SettingActivity.this.recreate();
    

For more detail and example code... have a look on Android multi theme implementation

Pankaj Jangid
  • 283
  • 2
  • 7