如何在Android中应用主题/样式而无需重新启动活动?

3
我有一个应用程序,用户可以从PreferenceActivity中选择几种不同的颜色主题,从而改变整个应用程序的主题/颜色。但是在PreferenceActivity中选择的更改不会立即应用。只有当用户重新进入PreferenceActivity时才应用更改。
我知道每次选择主题时都可以调用recreate(),但我想知道是否存在一种更好的解决方案,而不必重新创建整个活动。 以下是当前工作方式的视频:https://www.youtube.com/watch?v=oU8xIUi_48A 这是我在PreferenceActivity中设置首选项列表中选定值的位置:
@Override
public void onCreate(Bundle savedInstanceState) {
    setTheme();
    themecolorList.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            switch (themecolorList.getValue()) {

                case "grey":
                    themecolorList.getEditor().putString("grey", "green").apply();
                    break;
                case "green":
                    themecolorList.getEditor().putString("green", "green").apply();
                    setTheme(R.style.AppTheme_default);
                    break;
                case "blue":
                    themecolorList.getEditor().putString("blue", "green").apply();
                    break;
                case "yellow":
                    themecolorList.getEditor().putString("yellow", "green").apply();
                    break;
                case "red":
                    themecolorList.getEditor().putString("red", "green").apply();
                    break;
                case "pink":
                    themecolorList.getEditor().putString("pink", "green").apply();
                    break;

                default:
                    themecolorList.getEditor().putString("green", "green").apply();
                    break;
            }

            recreate();
            return true;


        }
    });
  }

在我的PreferenceActivity的onCreate()方法中调用了setTheme()方法。
private void setTheme() {

   SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    switch (sharedPreferences.getString("THEME_KEY", "green")) {

        case "grey":
            setTheme(R.style.AppTheme_Grey);
            break;

        case "green":
            setTheme(R.style.AppTheme_default);
            break;

        case "blue":
            setTheme(R.style.AppTheme_Blue);
            break;

        case "yellow":
            setTheme(R.style.AppTheme_Yellow);
            break;

        case "red":
            setTheme(R.style.AppTheme_Red);
            break;

        case "pink":
            setTheme(R.style.AppTheme_Pink);
            break;

        default:
            getApplication().setTheme(R.style.AppTheme_default);
            setTheme(R.style.AppTheme_default);
            break;
    }
}
5个回答

8
似乎最好的解决方案是使用recreate();由于没有其他方式来刷新一个活动的整个布局:
当用户从主题列表中选择选项时,通过OnPreferenceChangeListener将所选项的键/值保存在SharedPreference中,然后调用recreate();
themecolorList.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            recreate();
            return true;
        }
    });

在我的PreferenceActivityonCreate();中,我调用了一个自定义方法setTheme();,该方法在调用recreate();之后被调用。 setTheme();只是查找OnPreferenceChangeListener中保存在SharedPreference中的内容,并将主题设置为相应值。
 @Override
 public void onCreate(Bundle savedInstanceState) {
    setTheme();
    super.onCreate(savedInstanceState);
}

recreate() 方法会重新创建所有的活动。 - famfamfam

0

不行,您可以启动一个新活动以选择主题,并在用户完成该活动后进行操作。


使用recreate();比每次用户在首选项列表中按选项时启动新的Intent要更好。 - user5366495

0

触发布局更新(通过旋转设备或让应用程序认为它已经旋转)通常会导致其重新加载资源。

我现在不记得具体如何做了,但上次我调查类似的事情时,这是一种常见的做法。只需记住在清单中指定您的活动将处理布局更改/屏幕旋转,以避免完全重新启动(并且丢失任何未保存的数据)。


听起来是个不错的解决方案。唯一的问题是我已经让我的应用只在竖屏模式下运行,因为在横屏模式下使用它是不实际的。 - user5366495
哈哈,我之前也遇到了和你一样的问题! :p (https://dev59.com/MGbWa4cB1Zd3GeqPY6js#bVsFoYgBc1ULPQZFBh_e)。但是我认为你只能重新创建活动,或者你可以制作一个预览(图像弹出窗口,或者如果可能的话将样式颜色应用于列表项?),然后在用户进行选择时重新创建活动(如果需要,使用Bundle向新实例提供当前状态)。 - ToVine

0

你可以使用这个。对我有效。

@HiltAndroidApp
class App : Application(){

    companion object{
       private var isOpening = true
        fun appIsOpening(sync : (Boolean) -> Unit){
            sync(isOpening)
            isOpening = false
        }
    }

}

并且

@AndroidEntryPoint
class SingleActivity : AppCompatActivity() {

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

        App.appIsOpening { it ->
            if (it)setStartDestination()
        }
    }


}

-1

看起来有一个名为invalidate()的方法需要在需要重新绘制的视图上调用。

链接

这将允许您调用仅需要重新绘制的单个视图,而不是整个活动。


PreferenceActivityAppCompatPreferenceActivity 中,只有这些方法:invalidateOptionsMenu();invalidateHeaders();,但是它们都不起作用。 - user5366495
哦,我明白了,抱歉。 - Buildersrejected

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接