Моя ListPreference не меняет тему приложения во время выполнения - PullRequest
1 голос
/ 07 октября 2019

Как я могу заставить свой Activity воссоздать себя и остаться определенной темой, когда я выбираю элемент в ListPreference, чтобы изменить тему моего приложения? По какой-то причине мое приложение застряло на светлой теме, независимо от того, какой элемент в ListPreference выбран. Я не уверен, что я здесь сделал неправильно.

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light"/>

    <style name="MyDarkSettingsTheme" parent="Theme.AppCompat"/>

    <style name="MyLightSettingsTheme" parent="Theme.AppCompat.Light"/>

</resources>

Активность

class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
    // Declaring initial value for applying appropriate Theme
    private var mCurrentValue: Boolean = true // True is the default value

    override fun onCreate(savedInstanceState: Bundle?) {
        // Checking which Theme should be used. IMPORTANT: applying Themes MUST called BEFORE super.onCreate() and setContentView!!!
        val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
        mCurrentValue = mSharedPreferences.getBoolean("light", true)
        if (mCurrentValue) setTheme(R.style.MyLightSettingsTheme)
        else setTheme(R.style.MyDarkSettingsTheme)

        super.onCreate(savedInstanceState)
        setContentView(R.layout.settings_activity)
        supportFragmentManager
            .beginTransaction()
            .replace(R.id.settings, SettingsFragment())
            .commit()

        val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
        sharedPreferences.registerOnSharedPreferenceChangeListener(this)
    }

    // In order to recreate Activity, we must check the value here. Because, when we come back from another Activity, the onCreate isn't called again.
    override fun onStart() {
        super.onStart()

        setContentView(R.layout.settings_activity)
        supportFragmentManager
            .beginTransaction()
            .replace(R.id.settings, SettingsFragment())
            .commit()

        val mFrameLayout = findViewById<FrameLayout>(R.id.settings)

        val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
        val mNewValue = mSharedPreferences.getBoolean("light", true)
        // If value differs from previous Theme, recreate Activity
        if (mCurrentValue != mNewValue) recreate()

//        if (mNewValue) {
//            mFrameLayout.setBackgroundColor(Color.WHITE)
//        }
//        else {
//            mFrameLayout.setBackgroundColor(Color.BLACK)
//        }

        // ... do other stuff here

    }

    class SettingsFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.root_preferences, rootKey)
        }
    }

    override fun onDestroy() {
        val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
        //...
        super.onDestroy()
    }

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
        when (key) {
            "list_theme" -> {
                if (sharedPreferences.getString(key, "light") == "light") {
                    setTheme(R.style.MyLightSettingsTheme)
                    recreate()
                }
                else if (sharedPreferences.getString(key, "dark") == "dark") {
                    setTheme(R.style.MyDarkSettingsTheme)
                    recreate()
                }
            }
        }
    }
}

1) Открытое действие

enter image description here

2) СписокПреференция нажмите

enter image description here

3) Выбрано предпочтение темноты

enter image description here

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }


    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.action_settings -> {
                val intentSettings = Intent(this, SettingsActivity ::class.java)
                startActivity(intentSettings)
                true
            }

            else ->
                super.onOptionsItemSelected(item)
        }
    }
}

1 Ответ

0 голосов
/ 07 октября 2019

Во-первых, вам нужно добавить больше цветов / тем в ваш файл styles.xml.

Пример:

<!-- Base Light application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

<!--Dark Theme Default-->
<style name="AppThemeDark" parent="Theme.AppCompat">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

В моем классе Base Application я добавил эти 3методы. Мое приложение имеет 3 темы, если у вас их больше, вы можете соответствующим образом отредактировать код.

@Override
public void onCreate() {
    super.onCreate();
    PreferenceManager.setDefaultValues(this, R.xml.pref_main, false);
    Context context = this;
    context.setTheme(getUserTheme());
    mInstance = this;
    res = getResources();
    shared = PreferenceManager.getDefaultSharedPreferences(context);
}

public static int getTheme(Context context, int light, int dark, int amoled) {
    String darkTheme = context.getString(R.string.dark_mode_theme);
    String amoledTheme = context.getString(R.string.amoled_mode_theme);
    shared = PreferenceManager.getDefaultSharedPreferences(context);
    String theme = shared.getString(Constants.PREFERENCE_THEME, darkTheme);
    //Able to access these values outside the class!
    if (theme.equals(darkTheme)) {
        return dark;
    } else if (theme.equals(amoledTheme)) {
        return amoled;
    } else {
        return light;
    }
}

private int getUserTheme() {
    return getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
}

Если у вас нет класса, расширяющего Application, создайте его, а затем добавьте в AndroidMainfest, поместив эту строку в тег <Application>

 android:name="App"

Я также добавил следующие методы в Base Activity Class. Все мои действия расширяют этот класс. Если в вашем приложении есть только одно действие, это менее важно для вас.

protected abstract int getAppTheme(); //has to be implemented in anything that extends this class

protected void setAppTheme(int id) {
    super.setTheme(id);
    themeId = id;
}

 protected void onResume() {
        super.onResume()
        if (themeId !== getAppTheme())
        {
            recreate();
        }
    }

После изменения темы вам необходимо заново создать действие, чтобы активировать изменения.

recreate();

Вы не можете вызвать его из статического метода, к сожалению. Я также рекомендовал бы проверить тему в onCreate, и если текущая тема не соответствует выбранной пользователем теме, измените тему и затем вызовите recreate();.

Далее, в обычном действии, которое расширяетсябазовый класс активности, я добавил это. Обязательно держите его в одном и том же порядке везде. Если вы этого не сделаете, темы не будут соответствовать.

 public int getAppTheme() {
        return App.getTheme(this, R.style.AppTheme, R.style.AppThemeDark, R.style.AppThemeAMOLED);
    }
...