如何在不重启 activity 的情况下切换主题(夜间模式)?
How to switch themes (night mode) without restarting the activity?
我做了几个支持多主题的应用程序,但是当用户切换主题时我总是不得不重新启动应用程序,因为setTheme()
需要在setContentView()
之前调用。
在我发现这个应用程序之前,我对它很满意。它可以在两个主题之间无缝切换,transitions/animations也可以!
请给我一些关于这是如何实现的提示(以及动画)。谢谢!
没有任何东西阻止您再次调用 setTheme()
然后 setContentView()
。您只需要稍微重组您的应用程序,这样,如果您更改主题,您需要重新初始化您可能拥有的任何成员变量,这些变量持有对 View
对象的引用。
transition/animation 使主题在您重新启动 activity 时无缝更改,这可以通过将项目 "android:windowanimationStyle" 添加到您的主题,然后引用样式来完成您指定 Activity 在进入和退出时应如何设置动画。
请注意,这会使动画应用于具有该主题的所有活动。
<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
@Alexander Hanssen 的回答基本上已经回答了这个...
不知道为什么不被接受...可能是因为 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>
但不是 finish/start 的新意图:
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 或更新版本寻找解决方案的人。
设置dark/light模式使用这个:
AppCompatDelegate.setDefaultNightMode(state) //state can be AppCompatDelegate.MODE_NIGHT_YES or AppCompatDelegate.MODE_NIGHT_NO
它会改变您的应用程序的显示,但会闪烁
为了避免 activity 娱乐闪烁(为了平稳过渡),在您的 activity 中添加以下方法
@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);
}
setTheme() 在 GKA 中的 super.onCreate(savedInstanceState) 之前答案是完美的方法并且效果很好,感谢 GKA .
但它会再次为所有资源创建新实例,包括活动、片段和回收器视图。我认为这可能是繁重的工作并导致丢失一些保存的数据,如局部变量。
accourding to google document: https://developer.android.com/reference/android/app/Activity#recreate()
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to a
configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
还有另一种方法,您可以使用代码(Java 或 Kotlin)以编程方式更改主题,在这种方法中,您不需要重新创建所有资源,而且您还可以使用自定义动画,如涟漪.
检查我的 GitHub 图书馆:
https://github.com/imandolatkia/Android-Animated-Theme-Manager
在此库中,您可以创建自定义主题并使用涟漪动画动态更改它们,而无需重新创建任何资源。
在片段中简单有效的一个衬垫:
requireActivity().recreate();
对于activity:
recreate();
我做了几个支持多主题的应用程序,但是当用户切换主题时我总是不得不重新启动应用程序,因为setTheme()
需要在setContentView()
之前调用。
在我发现这个应用程序之前,我对它很满意。它可以在两个主题之间无缝切换,transitions/animations也可以!
请给我一些关于这是如何实现的提示(以及动画)。谢谢!
没有任何东西阻止您再次调用 setTheme()
然后 setContentView()
。您只需要稍微重组您的应用程序,这样,如果您更改主题,您需要重新初始化您可能拥有的任何成员变量,这些变量持有对 View
对象的引用。
transition/animation 使主题在您重新启动 activity 时无缝更改,这可以通过将项目 "android:windowanimationStyle" 添加到您的主题,然后引用样式来完成您指定 Activity 在进入和退出时应如何设置动画。 请注意,这会使动画应用于具有该主题的所有活动。
<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
@Alexander Hanssen 的回答基本上已经回答了这个... 不知道为什么不被接受...可能是因为 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>
但不是 finish/start 的新意图:
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 或更新版本寻找解决方案的人。
设置dark/light模式使用这个:
AppCompatDelegate.setDefaultNightMode(state) //state can be AppCompatDelegate.MODE_NIGHT_YES or AppCompatDelegate.MODE_NIGHT_NO
它会改变您的应用程序的显示,但会闪烁
为了避免 activity 娱乐闪烁(为了平稳过渡),在您的 activity 中添加以下方法
@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);
}
setTheme() 在 GKA 中的 super.onCreate(savedInstanceState) 之前答案是完美的方法并且效果很好,感谢 GKA .
但它会再次为所有资源创建新实例,包括活动、片段和回收器视图。我认为这可能是繁重的工作并导致丢失一些保存的数据,如局部变量。
accourding to google document: https://developer.android.com/reference/android/app/Activity#recreate()
Cause this Activity to be recreated with a new instance. This results in essentially the same flow as when the Activity is created due to a configuration change -- the current instance will go through its lifecycle to onDestroy() and a new instance then created after it.
还有另一种方法,您可以使用代码(Java 或 Kotlin)以编程方式更改主题,在这种方法中,您不需要重新创建所有资源,而且您还可以使用自定义动画,如涟漪.
检查我的 GitHub 图书馆: https://github.com/imandolatkia/Android-Animated-Theme-Manager
在此库中,您可以创建自定义主题并使用涟漪动画动态更改它们,而无需重新创建任何资源。
在片段中简单有效的一个衬垫:
requireActivity().recreate();
对于activity:
recreate();