Как переключать темы (ночной режим) без перезапуска активности?
Я сделал несколько приложений, которые поддерживают несколько тем, но мне всегда приходилось перезапускать приложение, когда пользователь переключает тему, потому что setTheme()
нужно позвонить раньше setContentView()
,
Я был в порядке с этим, пока я не обнаружил это приложение. Он может легко переключаться между двумя темами, а также с переходами / анимацией!
Пожалуйста, дайте мне несколько советов о том, как это было реализовано (и анимации тоже). Спасибо!
7 ответов
Ответ Александра Хансена в основном ответил на это... Не знаю, почему он не был принят... Может быть, из-за 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: 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
setTheme() перед super.onCreate(savedInstanceState) в ответе GKA - идеальный подход и хорошо работает, благодаря GKA.
но он снова создает новые экземпляры для всех ресурсов, включая действия, фрагменты и представления ресайклера. Я думаю, что это может быть тяжелая работа и привести к потере некоторых сохраненных данных, таких как локальные переменные.
в соответствии с документом Google: https://developer.android.com/reference/android/app/Activity#recreate()
Заставить это действие быть воссозданным с новым экземпляром. Это приводит к тому же потоку, что и при создании Activity из-за изменения конфигурации - текущий экземпляр проходит свой жизненный цикл до onDestroy (), а после него создается новый экземпляр.
есть другой подход, в котором вы можете программно изменить тему с помощью кода (Java или Kotlin), при этом вам не нужно воссоздавать все ресурсы, а также вы можете использовать настраиваемую анимацию, такую как рябь.
проверьте мою библиотеку GitHub:https://github.com/imandolatkia/Android-Animated-Theme-Manager
в этой библиотеке вы можете создавать свои собственные темы и динамически изменять их с помощью анимации ряби без воссоздания каких-либо ресурсов.
для тех, кто пытается найти решение для 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);
}
Просто эффективный однострочник во фрагменте:
requireActivity().recreate();
По активности:
recreate();
Ничто не мешает вам звонить setTheme()
а потом setContentView()
снова. Вам просто нужно немного реструктурировать свое приложение, чтобы при смене темы вам нужно было повторно инициализировать любые переменные-члены, которые могут содержать ссылки на View
объекты.
Все приведенные выше ответы на самом деле не препятствуют воссозданию активности! Правильное решение должно быть таким:
- Добавьте «uiMode» в поле configChanges в
AndroidManifest.xml
чтобы избежать повторного создания активности при переключении темного режима.
Android:configChanges="uiMode"
- Обновите цвет всех видов вручную, когда включен темный режим.
onConfigureChanged()
функция в Activity.
Для получения более подробной информации вы можете обратиться к этой статье:https://proandroiddev.com/daynight-applying-dark-mode-without-recreating-your-app-c8a62d51092d .