如何切换主题(夜间模式)而不重新启动活动?

我已经做了一些应用程序,支持多个主题,但我总是不得不重新启动应用程序时,用户切换主题,因为 setTheme()需要在 setContentView()之前调用。

在我发现这个应用程序之前,我都没有意见。它可以无缝切换两个主题,并与过渡/动画太!

enter image description here

请给我一些关于这是如何实现(和动画)的提示。谢谢!

31222 次浏览

没有什么能阻止你调用 setTheme()然后再调用 setContentView()。您只需要稍微重构一下您的应用程序,这样,如果您更改了主题,您就需要重新初始化您可能拥有的包含对 View对象引用的任何成员变量。

当你重新启动活动时,转换/动画使得主题变化无缝,这可以通过添加项目“ android: windowanimationStyle”到你的主题中,然后引用一个样式,在这个样式中你指定活动进入和退出时应该如何动画。 注意,这使得动画应用于该主题的所有活动。

<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>

然后,当你想改变主题时,你可以点击一个按钮:

AppSettings settings = AppSettings.getInstance(this);
settings.set(AppSettings.Key.USE_DARK_THEME,
!settings.getBoolean(AppSettings.Key.USE_DARK_THEME));
Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();

然后在 onCreate方法中,使用 setTheme()应用当前在 AppSettings 中设置的主题,如下所示:

AppSettings settings = AppSettings.getInstance(this);
setTheme(settings.getBoolean(AppSettings.Key.USE_DARK_THEME) ? R.style.AppThemeDark : R.style.AppThemeLight);
super.onCreate(savedInstanceState);
setContentView(<yourlayouthere>);

参考以下要点: https://gist.github.com/alphamu/f2469c28e17b24114fe5

@ 亚历山大 · 汉森的回答基本上回答了这个问题..。 不知道为什么它没有被接受... 可能是因为 Finish ()/startActivity ()。 我投了赞成票,我试图发表评论,但不能..。

不管怎样,我会按照他描述的风格来做。

<style name="AppThemeLight" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
</style>
<!-- This will set the fade in animation on all your activities by default -->
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
</style>

但是,不要以新的意图结束/开始:

Intent intent = new Intent(this, <yourclass>.class);
startActivity(intent);
finish();

我会这么做:

@Override
protected void onCreate(Bundle savedInstanceState) {


// MUST do this before super call or setContentView(...)
// pick which theme DAY or NIGHT from settings
setTheme(someSettings.get(PREFFERED_THEME) ? R.style.AppThemeLight : R.style.AppThemeDark);


super.onCreate(savedInstanceState);
}


// Somewhere in your activity where the button switches the theme
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {


// decide which theme to use DAY or NIGHT and save it
someSettings.save(PREFFERED_THEME, isDay());


Activity.this.recreate();
}
});

效果如视频中所示..。

对于那些试图找到解决方案的 android 版本10或更新。

设置黑暗/光明模式使用:

AppCompatDelegate.setDefaultNightMode(state) //state can be AppCompatDelegate.MODE_NIGHT_YES or AppCompatDelegate.MODE_NIGHT_NO

它将改变你的应用程序的显示,但有一个闪烁

为了避免活动再现闪烁(为了平稳过渡) ,在活动中添加以下方法

@Override
public void recreate() {
finish();
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
startActivity(getIntent());
overridePendingTransition(R.anim.anime_fade_in,
R.anim.anime_fade_out);
}

GKA 答案中 OnCreate (savedInstanceState)之前的 setTheme () 是完美的方法,并且工作得很好,这要感谢 GKA。

但是它再次为所有资源创建新的实例,包括活动、片段和回收者视图。我认为这可能是繁重的工作,导致丢失一些保存的数据,如局部变量。

根据谷歌文档: https://developer.android.com/reference/android/app/Activity#recreate()

使用一个新实例重新创建此活动 在基本相同的流中,当活动由于 配置更改——当前实例将通过其 生命周期到 onDestroy () ,然后在它之后创建一个新实例。

还有另一种方法,你可以通过代码(Java 或 Kotlin)编程式地改变主题,在这种方法中,你不需要重新创建所有的资源,而且你也可以使用自定义动画像涟漪。

查看我的 GitHub 库: Https://github.com/imandolatkia/android-animated-theme-manager

在这个库中,您可以创建自定义主题,并使用涟漪动画动态更改它们,而无需重新创建任何资源。

enter image description here

简单有效的碎片中的一行:

requireActivity().recreate();

活动:

recreate();