Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I made settings activity from Android Studio, not manually. I want to make a switch that applies a dark mode in the app. The problem is that when I click the switch there is no animation for movement, only a blink from the app. When I go back in my Main Activity I see that the theme is applied(I have tried earlier only with the main activity), but when I try to go back in the settings everything is frozen! Nothing can be clicked, no reaction at all. This is my Java code:

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;

public class SettingsActivity extends AppCompatActivity {
    private SwitchPreference darkModeSwitch;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings_activity);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.settings, new SettingsFragment())
                .commit();
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);

        }
    }

    public static class SettingsFragment extends PreferenceFragmentCompat {
        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey);
            SwitchPreference darkModeSwitch = (SwitchPreference) findPreference("darkmode");
            assert darkModeSwitch != null;
            darkModeSwitch.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                    } else {
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                    }
                    return false;
                }
            });
        }
    }
}

This is root_preferences.xml:

<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">

<PreferenceCategory
    app:title="General">

    <SwitchPreference
        app:key="darkmode"
        app:title="Dark mode"/>
</PreferenceCategory>

And this is the Logcat after applying the theme:

avc: denied { getattr } for path="/proc/1" dev="proc" ino=3924 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:r:init:s0 tclass=dir permissive=0

I think that it may be because I have not started the activity again after applying the theme, because when I tried the dark mode in main_activity, there were two lines, which in my settings activity cannot be placed, because the class is static... Please help!

public void onClick(View v) {
                if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                } else {
                    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                }
//These two
            finish();
            startActivity(new Intent(MainActivity.this, MainActivity.this.getClass()));
        }
    });
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
151 views
Welcome To Ask or Share your Answers For Others

1 Answer

Put this in your preferences.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
    <SwitchPreferenceCompat
        app:defaultValue="false"
        app:key="@string/key_night_mode"
        app:summaryOff="@string/summary_night_mode_off"
        app:summaryOn="@string/summary_night_mode_on"
        app:title="@string/title_night_mode" />
</PreferenceScreen>

Then in your SettingsFragment.java which extended PreferenceFragmentCompat inside the onCreatePreference() method:

    SwitchPreferenceCompat switchPreferenceCompat = findPreference(getString(R.string.key_night_mode));

    switchPreferenceCompat.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    boolean isChecked = false;
                    if (newValue instanceof Boolean)
                        isChecked = (Boolean) newValue;
                    if (isChecked) {
                    //these lines so that the preference persists
getPreferenceManager().getSharedPreferences().edit().putBoolean(getString(R.string.key_night_mode), true).apply();
                    //you do not need to finish and recreate activity
                    //it takes care of any such things that needs to be done  
                    //automatically
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
                    } else {
                        getPreferenceManager().getSharedPreferences().edit().putBoolean(getString(R.string.key_night_mode), false).apply();
                        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
                    }
                    return true;
                }
            });

These lines of codes are working for me.


Note:

  1. AppTheme should extends from Theme.AppCompat.DayNight or Theme.MaterialComponents.DayNight if you want to be dependent on platform for your night theme. Otherwise, you can create your separate Day and Night theme which extends from Theme.MaterialComponents.Light and Theme.MaterialComponents respectively(AppCompat has similar set of themes too).
  2. Every time the app starts, it needs to respect the user's preferences and start in the user setted theme accordingly. To achieve this, you can check the preference and set theme in the MyApplication class as follows:

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        boolean nightMode = sharedPreferences.getBoolean(getString(R.string.key_night_mode), false);
        if (nightMode)
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        else {
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P)
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
            else
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
        }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...