Sobes.tech
Junior

¿Cómo guardar y usar la configuración del tema en una aplicación de Android?

sobes.tech AI

Respuesta de la IA

Un enfoque efectivo incluye el uso de SharedPreferences para guardar el tema seleccionado y AppCompatDelegate.setDefaultNightMode() para aplicarlo.

  1. Guardar el tema: Utiliza SharedPreferences para almacenar el identificador del tema seleccionado (por ejemplo, "light", "dark", "system").

    // Obtener SharedPreferences
    val sharedPrefs = getSharedPreferences("AppTheme", Context.MODE_PRIVATE)
    // Obtener el editor
    val editor = sharedPrefs.edit()
    // Aplicar el tema con ID themeId
    editor.putString("current_theme", themeId)
    // Guardar cambios
    editor.apply()
    
  2. Aplicar el tema al iniciar: En la Activity principal o en la clase Application, lee el valor guardado en SharedPreferences y aplica el tema.

    // Leer el valor guardado del tema
    val themeId = getSharedPreferences("AppTheme", Context.MODE_PRIVATE)
        .getString("current_theme", "system") // Por defecto 'system'
    
    // Aplicar el tema
    when (themeId) {
        "light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
        "dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
        "system" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
        else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
    }
    
  3. Cambio de tema por parte del usuario: Proporciona una interfaz de usuario (por ejemplo, RadioButton en configuraciones), donde el usuario pueda seleccionar el tema. Al seleccionar, guarda el nuevo identificador en SharedPreferences y aplica inmediatamente el tema llamando a AppCompatDelegate.setDefaultNightMode(), y si es necesario, reinicia la Activity para aplicar correctamente el tema.

    // Supongamos que el usuario eligió tema oscuro
    val sharedPrefs = getSharedPreferences("AppTheme", Context.MODE_PRIVATE)
    val editor = sharedPrefs.edit()
    editor.putString("current_theme", "dark")
    editor.apply()
    
    // Aplicar el tema inmediatamente
    AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    
    // O usar recreate() para aplicar completamente el tema
    // recreate()
    

Reiniciar la Activity con recreate() puede ser necesario para que todas las vistas en la Activity actual se redibujen correctamente con el nuevo tema.

  1. Definición de temas en styles.xml: Define estilos para los temas claro y oscuro en res/values/styles.xml y res/values-night/styles.xml respectivamente, heredando de los temas Theme.AppCompat.

    <!-- res/values/styles.xml -->
    <style name="AppTheme.Light" parent="Theme.AppCompat.Light">
        <!-- Definiciones de estilos para tema claro -->
    </style>
    
    <!-- res/values-night/styles.xml -->
    <style name="AppTheme.Dark" parent="Theme.AppCompat">
        <!-- Definiciones de estilos para tema oscuro -->
    </style>
    

En AndroidManifest.xml, especifica el tema base de la aplicación:

```xml
<!-- AndroidManifest.xml -->
<application
    android:theme="@style/AppTheme.Light"
    ...>
    <!-- ... Activities -->
</application>
```
  1. Escuchar cambios de tema: En caso de cambios en el sistema (por ejemplo, por horario o manualmente por el usuario en la configuración del teléfono), puedes usar Configuration.uiMode en onConfigurationChanged() para reaccionar, pero AppCompatDelegate generalmente maneja esto automáticamente cuando usas MODE_NIGHT_FOLLOW_SYSTEM.

    @Override
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        // Puedes verificar el nuevo tema si es necesario
        // val currentNightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
        // ...
    }
    

El uso de AppCompatDelegate es el enfoque recomendado para soportar temas en Android, ya que proporciona compatibilidad hacia atrás y funcionamiento correcto con diferentes componentes de la biblioteca de soporte.