#android #android-layout #android-activity
#Android #android-layout #android-активность
Вопрос:
Я пытаюсь изменить тему своего приложения во время выполнения
У меня есть класс ChangeTheme и класс Utility (SharedPreferences)
ChangeTheme.java
public class ChangeTheme extends AppCompatActivity {
private final static int THEME_LIGHT = 1;
private final static int THEME_DARK = 2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.change_theme_activity);
updateTheme();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.myoptions,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.theme:
Intent toChangeTheme = new Intent(ChangeTheme.this,ChangeTheme.class);
startActivity(toChangeTheme);
}
return true;
}
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
// Check which radio button was clicked
switch(view.getId()) {
case R.id.lightTheme:
if (checked){
setTheme(R.style.AppTheme);
}
break;
case R.id.darkTheme:
if (checked){
setTheme(R.style.AppThemeDark);
}
break;
}
}
public void updateTheme() {
if (Utility.getTheme(getApplicationContext()) <= THEME_LIGHT) {
setTheme(R.style.AppTheme);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimary));
}
} else if (Utility.getTheme(getApplicationContext()) == THEME_DARK) {
setTheme(R.style.AppThemeDark);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().setStatusBarColor(getResources().getColor(R.color.colorSecondary));
}
}
}
}
change_theme_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="12dp"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<TextView
android:id="@ id/textTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Change Theme To:"
android:layout_marginTop="125dp">
</TextView>
<RadioGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="20dp">
<RadioButton
android:id="@ id/lightTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Light Theme"
android:onClick="onRadioButtonClicked"/>
<RadioButton
android:id="@ id/darkTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dark Theme"
android:onClick="onRadioButtonClicked"/>
</RadioGroup>
</LinearLayout>
Utility.java
public class Utility {
public static void setTheme(Context context, int theme) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putInt(context.getString(R.string.prefs_theme_key), theme).apply();
}
public static int getTheme(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getInt(context.getString(R.string.prefs_theme_key), -1);
}
}
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppThemeDark" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorSecondary</item>
<item name="colorPrimaryDark">@color/colorSecondaryDark</item>
<item name="colorAccent">@color/colorSecondaryAccent</item>
</style>
</resources>
When i click in the buttons to change the theme nothing happens, why?
Can you help me?
I’ve already checked similar questions but nothing’ve helped
Update 2020/09/08
ChangeTheme.java
public class ChangeTheme extends AppCompatActivity {
private final static int THEME_LIGHT = 1;
private final static int THEME_DARK = 2;
private RadioButton lightThemeButton;
private RadioButton darkThemeButton;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.change_theme_activity);
lightThemeButton = (RadioButton) findViewById(R.id.lightTheme);
darkThemeButton = (RadioButton) findViewById(R.id.darkTheme);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.myoptions,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.theme:
Intent toChangeTheme = new Intent(ChangeTheme.this,ChangeTheme.class);
startActivity(toChangeTheme);
}
return true;
}
public void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
// Check which radio button was clicked
switch(view.getId()) {
case R.id.lightTheme:
if (checked){
Utility.changeToTheme(this, Utility.THEME_LIGHT);
}
break;
case R.id.darkTheme:
if (checked){
Utility.changeToTheme(this, Utility.THEME_DARK);
}
break;
}
}
}
Utility.java
public class Utility {
private static int sTheme;
public final static int THEME_LIGHT = 0;
public final static int THEME_DARK = 1;
//Set the theme of the Activity, and restart it by creating a new Activity of the same type.
public static void changeToTheme(Activity activity, int theme)
{
sTheme = theme;
activity.finish();
activity.startActivity(new Intent(activity, activity.getClass()));
}
//Set the theme of the activity, according to the configuration. */
public static void onActivityCreateSetTheme(Activity activity)
{
switch (sTheme)
{
default:
case THEME_LIGHT:
activity.setTheme(R.style.AppTheme);
break;
case THEME_DARK:
activity.setTheme(R.style.DarkTheme);
break;
}
}
}
styles.xml
<color name="color_primary_grey">#212121</color>
<color name="color_primary_black">#000000</color>
<color name="color_accent_white">#aeaeae</color>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="DarkTheme" parent="AppTheme">
<item name="colorPrimary">@color/color_primary_grey</item>
<item name="colorPrimaryDark">@color/color_primary_black</item>
<item name="colorAccent">@color/color_accent_white</item>
</style>
Что мне нужно сделать сейчас, чтобы я мог изменить тему во время выполнения?
Ответ №1:
Я делал это раньше для своего приложения.
Для моего решения я следовал подходу, представленному в этом руководстве.
Вот шаги, которые нужно предпринять:
- сохраняйте имя (или идентификатор) темы в общих настройках. Вы это уже сделали
- в методе onCreate вашей активности получите эту строку / ИДЕНТИФИКАТОР темы (определенный в стилях), который должен быть применен, как показано ниже:
// inside activities onCreate method
// Within your switch command each case should look like this
theme.applyStyle(R.style.AppColorsDefault, true) // in Java it should be getTheme()
// for other cases just replace the style
theme.applyStyle(R.style.AppColorsDark, true) // true forces overwriting attributes that are -potentially - defined by your AppTheme
- Перезапустите свою активность, чтобы изменения вступили в силу (темы могут быть установлены только в вашем методе onCreate, поэтому вам необходимо перезапустить свою активность)
val intent = requireActivity().intent // use Intent intent = getActivity().getIntent() in Java
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
requireActivity().finish() // use getActivity() again
startActivity(intent)
В моем решении вам также не нужно наследовать тему. Применяемый стиль должен содержать только изменения.
Вот пример:
styles.xml
<resources>
<!-- Base application theme.
Also consider using a Material Theme
Theme.MaterialComponents.Light.DarkActionBar
-->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<!-- put all the attributes here that should be applied to the app independent from the applied colors -->
</style>
<style name="AppColorsDefault">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppColorsDark">
<item name="colorPrimary">@color/colorSecondary</item>
<item name="colorPrimaryDark">@color/colorSecondaryDark</item>
<item name="colorAccent">@color/colorSecondaryAccent</item>
</style>
</resources>
Если ваше приложение имеет более одного действия, и вы хотите, чтобы ваш измененный стиль (например, цвета) был применен ко всем из них:
Просто создайте BaseActivity
это extends AppCompatActivity
, и пусть все ваши действия расширяют это BaseActivity
Комментарии:
1. Хорошо, тогда я предполагаю, что вы не пытаетесь вызвать его из фрагмента? Проще всего было бы вызвать finish в вашей основной деятельности. Не могли бы вы превратить свой класс ChangeTheme во фрагмент или, в конечном итоге, в сопоставимый фрагмент предпочтений ?
2. В моем ответе посмотрите на шаг 2: вызовите этот метод oncreate в activity, чтобы применить этот стиль. Если вы хотите, чтобы она применялась ко всем действиям, затем создайте пустое действие с помощью этого метода onCreate и разрешите всем действиям расширять его.
3. Ваша операция ChangeTheme делает гораздо больше, чем просто применение темы. Нет необходимости наследовать эту логику выбора темы для любого другого действия.
4. Вы удалили весь свой предыдущий код. Может быть, в следующий раз просто опубликуйте обновление, чтобы мы могли видеть, с чего вы начали и как вы пришли к окончательному решению, которое решило вашу проблему. Пожалуйста, взгляните на ваши стили в сравнении с моими предложенными стилями. Отделите цвета от базовой темы, которая наследуется от тем AppCompat
5. Использование фрагмента экрана предпочтений вместо вашего предыдущего подхода с использованием пользовательского действия было всего лишь предложением, потому что в конечном итоге это упростит вашу задачу. На экране настроек вы также можете использовать ListPreference. Вы можете найти пример здесь .