实现用户选择的主题

Mat*_*ris 33 android android-theme

我想让用户在几个不同的主题之间做出选择,并且想知道这是否是一种正常的做事方式.我用这种方法进行了一些测试并且它有效,但我认为可能有更好的方法并认为它可能会在以后引起一些问题,所以想问一下.

我正在考虑为每个主题创建一个不同的布局,并且onCreate只是为setContentView()方法切换.我首先加载一个保存的SharedPreference值(整数),具体取决于显示相应布局的值.显然,用户可以SharedPreference使用按钮或其他内容更改值.

由于这些布局基本相同但颜色不同,我想TextViews在每个布局文件中为我和其他视图使用相同的ID .我的主要问题是这会导致问题吗?

抱歉没有代码的文本墙.我想对这种情况大致了解良好做法.提前致谢.

use*_*567 46

我实际上在我的应用程序中有这个功能,另外,我允许用户在运行时更改主题.从首选项中读取值需要一些时间,我通过全局可访问函数获取主题ID,该函数包含缓存值.

正如已经指出的那样 - 使用本指南创建一些Android主题.您<style>styles.xml文件中至少有两个项目.例如:

<style name="Theme.App.Light" parent="@style/Theme.Light">...</style>
<style name="Theme.App.Dark" parent="@style/Theme">...</style>
Run Code Online (Sandbox Code Playgroud)

现在,您必须将其中一种样式应用于您的活动.onCreate在任何其他电话之前,我在activitie的方法中这样做:

setTheme(MyApplication.getThemeId());
Run Code Online (Sandbox Code Playgroud)

getThemeId 是一个返回缓存主题ID的方法:

public static int getThemeId()
{
    return themeId;
}
Run Code Online (Sandbox Code Playgroud)

该字段正在通过另一种方法更新:

public static void reloadTheme()
{
    themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0");
    if(themeSetting.equals("0"))
        themeId = R.style.Theme_Light;
    else
        themeId = R.style.Theme_Dark;
}
Run Code Online (Sandbox Code Playgroud)

无论何时更改首选项(当然,在启动时)都会调用它.这两个方法驻留在MyApplication类中,它扩展了Application.首选更改侦听器在本文末尾描述并驻留在主要活动类中.

最后也是非常重要的事情 - 在活动开始时应用主题.假设,您只能在首选项屏幕中更改主题,并且只有一种方式可以实现,即只从一个(主要)活动开始,当您退出首选项屏幕时,此活动将不会重新启动 - 旧主题仍将是用过的.这是解决方法(重新启动主要活动):

@Override
protected void onResume() {
    super.onResume();
    if(schduledRestart)
    {
        schduledRestart = false;
        Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(i);
    }
}
Run Code Online (Sandbox Code Playgroud)

scheduledRestart是一个布尔变量,最初设置为false.当此侦听器更改主题时,它设置为true,该侦听器还更新之前提到的缓存主题ID:

private class ThemeListener implements OnSharedPreferenceChangeListener{

    @Override
    public void onSharedPreferenceChanged(SharedPreferences spref, String key) {
        if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting()))
        {
            MyApplication.reloadTheme();
            schduledRestart = true;
        }
    }


sp = PreferenceManager.getDefaultSharedPreferences(this);

listener = new ThemeListener();
sp.registerOnSharedPreferenceChangeListener(listener);
Run Code Online (Sandbox Code Playgroud)

记得保持对侦听器对象的引用,否则它将被垃圾收集(并将停止工作).

  • 看起来现在有一种更简单的重启活动的方法:`recreate`(https://developer.android.com/reference/android/app/Activity.html#recreate%28%29). (5认同)

Bha*_*esh 7

如果您使用材质组件主题并遵循浅色和深色主题指南,那么您可以从AppCompatDelegate. 这些主题可以在运行时更改/应用,而无需重新启动应用程序。

private fun handleThemeChange(theme: String) {
        when (newTheme) {
            getString(R.string.light) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
            getString(R.string.dark) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
            getString(R.string.system) -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)

        }
    }
Run Code Online (Sandbox Code Playgroud)