Crear Fragmento De Preferencias

El primer momento para diseñar una pantalla de ajustes en tus Apps Android se da al crear el fragmento de preferencias que muestre la jerarquía de opciones.

Apariencia de fragmento de preferencias en AndroidX

Por lo que en este tutorial aprenderás a:

  • Crear una jerarquía de preferencias en XML y en Kotlin
  • Inflar la jerarquía sobre el fragmento de tu pantalla de preferencias
  • Obtener la referencia de una preferencia
  • Procesar clicks sobre una preferencia

Ejemplo Para Crear Fragmento De Preferencias

En este tutorial crearemos el proyecto base en Android Studio que estudiaremos a lo largo de la guía de preferencias (todo):

Ejemplo de fragmento de preferencias en AndroidX

Ya que es la introducción, la interfaz es sencilla. Tendremos una sola preferencia asociada al ajuste de la versión de compilación de nuestra App. Puedes descargar el código desde aquí:

Con esto en mente, veamos el contexto de componentes a usar.


Fragmento De Preferencias

La clase PreferenceFragmentCompat es el punto de entrada para usar las características de la librería AndroidX Preferences. Por lo que los elementos de UI, acciones y almacenamiento de los valores de preferencias estarán ligados a este elemento.

Cada preferencia es materializada por la clase Preference y se ubica al interior de un elemento PreferenceScreen (u concepto similar a la construcción de layouts). Al construir la jerarquía, pasamos a inflarla sobre el fragmento.

Organizando estas ideas, nuestro plan será el siguiente:

  1. Crear proyecto Android Studio con una actividad principal
  2. Añadir un menú de opciones para iniciar los ajustes
  3. Crear actividad de ajustes
  4. Crear la jerarquía vía XML
  5. Inflar jerarquía sobre fragmento

Una vez construida la interfaz, pasaremos a manejar los eventos sobre la preferencia.

Sabiendo los pasos a seguir, comencemos a implementarlos:


1. Crear Proyecto En Android Studio

Abre Android Studio y crea un nuevo proyecto basado en la plantilla Empty Activity para generar una actividad inicial vacía.

Debido a que usaremos la librería de preferencias, añadiremos la siguiente dependencia en el archivo build.gradle del módulo con la última versión:

dependencies {  
    // ...
    implementation "androidx.preference:preference-ktx:ultima_version"
}

2. Crear Opción De Ajustes En Menú

Lo siguiente será añadir un nuevo recurso de menú con un solo ítem de acción para navegar hacia la futura actividad de ajustes.

Así que añade un nuevo archivo a la carpeta res/menu con el nombre de main_menu.xml y luego crea una etiqueta <item> en su interior:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/settings"
        android:title="@string/settings" />
</menu>

Luego abre la actividad principal y sobrescribe los controladores de inflado y procesamiento de clicks para el menú de opciones:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (R.id.settings == item.itemId) {
            toSettings()
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    private fun toSettings() {
        val intent = Intent(this, SettingsActivity::class.java)
        startActivity(intent)
    }
}

Evidentemente SettingsActivity aún no existe, por lo que crearla será nuestro siguiente paso.


3. Crear Actividad De Ajustes

Desde tu paquete haz click derecho y selecciona New>Activity>Empty Activity. Usa como nombre SettingsActivity.

En seguida, abre su layout activity_settings.xml y asígnale a su único nodo el id settings_container:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/settings_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SettingsActivity">

</androidx.constraintlayout.widget.ConstraintLayout>

Recuerda que necesitaremos un contenedor identificable para poder realizar la transacción del fragmento de ajustes más adelante.

Si ejecutas la aplicación podrás navegar desde el botón de acción que se despliega desde el overflow en la app bar.

Abrir actividad de ajustes con PreferenceFragmentCompat

Con estos componentes construidos, pasemos a incluir las instrucciones sobre las preferencias.


4. Crear Jerarquía De Preferencias

Añade un nuevo archivo llamado preferences.xml al directorio res/xml. Indica en la ventana de creación, que deseas que el nodo padre sea un elemento PreferenceScreen:

Crear archivo de jerarquía de preferencias en Android Studio

Una vez creado, ya tienes el lienzo para incluir tantos elementos Preference (o sus descendientes) como desees.

Editor de prefeferencias en Android Studio

En nuestro caso concreto, comenzaremos añadiendo una sola etiqueta <Preference> por simplicidad:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
    <Preference
        app:key="buildVersion"
        app:summary="1.0.0"
        app:title="Versión de compilación" />
</PreferenceScreen>

La clase Preference es el bloque de construcción básico de una jerarquía de preferencias. En esta forma solo consiste de un texto principal y su resumen:

Ejemplo de preferencia para versión de compilación en Android

Los atributos base usados tienen el siguiente propósito:

  • app:key: Representa la clave de la preferencia para almacenar su valor
  • app:title: Título de la preferencia. Expone el significado de la opción
  • app:summary: Es el texto secundario que aparece por debajo del título. Su propósito es brindar información sobre el estado actual de la preferencia

5. Inflar Jerarquía De Preferencias

Aquí entre en juego la creación de un fragmento que extienda de PreferenceFragmentCompat.

Ejemplo de FragmentPreferenceCompat

A diferencia de la clase Fragment, sobrescribiremos el controlador onCreatePreferences() para inflar el archivo preferences.xml con el método setPreferencesFromResource():

class SettingsFragment : PreferenceFragmentCompat() {

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences, rootKey)
    }
}

El método onCreatePreferences() es llamado desde onCreate() del fragmento para inflar la interfaz. Por esta razón recibe como primer parámetro el estado anterior si el fragmento se está recreando.

rootKey es el atributo android:key del elemento PreferenceScreen del recurso XML. Si no es null, es usado para asociar el fragmento a dicho elemento.

Finalizamos la actividad de ajustes, instalando el fragmento con una transacción a través del manejador de fragmentos:

class SettingsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_settings)
        if (savedInstanceState == null) {
            supportFragmentManager
                .beginTransaction()
                .replace(R.id.settings_container, SettingsFragment())
                .commit()
        }
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
    }
}

Nota: Es posible crear el fragmento de preferencias automáticamente yendo a New>Fragment>Settings Fragment. Android Studio creará la clase Kotlin y el archivo XML con la jerarquía por ti.


6. Encontrar Una Preferencia

Supongamos que deseas modificar el título de la preferencia de versión en tiempo de ejecución.

¿Cómo accedes a esta?

Al igual que con los views, puedes obtener la referencia de una preferencia en la jerarquía, a través del método findPreference() y su clave:

class SettingsFragment : PreferenceFragmentCompat() {

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences, rootKey)

        val buildVersion: Preference? = findPreference("buildVersion")
        buildVersion?.summary = BuildConfig.VERSION_NAME
    }
}

Una vez conseguido el objeto, simplemente accedes a sus propiedades para el cambio.

En el ejemplo concreto del título será Preference.summary, donde asignamos la constante VERSION_NAME producida por la construcción del proyecto.


7. Manejar Eventos De Click En Preferencia

Existen dos formas de establecer las acciones que se ejecutan cuando una preferencia es tocada: añadir un Intent o una escucha OnPreferenceClickListener.

Veamos cómo aplicar ambos casos:

Asignar Intent A Preferencia

Puedes especificar un intent para la preferencia tanto desde la definición XML como de su propiedad Kotlin.

Asignar Intent a preferencia en Android

Por ejemplo, supongamos que deseamos iniciar un navegador que muestre la URL de la página de ayuda asociada a nuestra preferencia:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <Preference
        app:key="buildVersion"
        app:summary="1.0.0"
        app:title="Versión de compilación">
        <intent
            android:action="android.intent.action.VIEW"
            android:data="http://www.develou.com/fragmento-de-preferencias-androidx" />
    </Preference>
</PreferenceScreen>

Hacerlo consiste en crear una etiqueta <intent> al interior de la preferencia. Luego usa la acción VIEW en android:action y la URL objetivo en android:data.

Por otra parte, el caso equivalente desde Kotlin requiere que obtengas la preferencia y asignarle el Intent previamente construido a Preference.intent:

val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("http://www.develou.com")
buildVersion?.intent = intent

Asignar Escucha OnPreferenceClickListener

Adicionalmente puedes usar a OnPreferenceClickListener para recibir el consumo de eventos desde su método onPreferenceClick():

buildVersion?.setOnPreferenceClickListener {
    Log.d("SettingsFragment", "\"${it.title}\" fue clickeada")
    false
}

A diferencia de asignar un intent, esta escucha te da libertad para ejecutar cualquier tipo de lógica en tiempo de ejecución. Retornas true para especificar si el click fue manejado o false en caso contrario.

El código anterior despliega el siguiente mensaje en el Logcat:

D/SettingsFragment: "Versión de compilación" fue clickeada

8. Crear Preferencias Desde Kotlin

Por otro lado, si deseas construir en tiempo de ejecución la jerarquía con Kotlin, entonces realiza la composición en el método onCreatePreferences() del fragmento:

class SettingsFragment : PreferenceFragmentCompat() {
    
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        val context = preferenceManager.context
        val screen = preferenceManager.createPreferenceScreen(context)

        val buildVersionPreference = Preference(context).apply {
            key = "buildVersion"
            setTitle(R.string.build_version_preference)
            summary = BuildConfig.VERSION_NAME
        }

        screen.addPreference(buildVersionPreference)
        preferenceScreen = screen
    }
}

La creación se resume a:

  1. Crear un componente PreferenceScreen con la clase de utilidad PreferenceManager
  2. Crear preferencia o categoría (todo) desde su constructor. Puedes usar apply() para configurar los atributos deseados.
  3. Añadir la preferencia a la pantalla con addPreference()
  4. Asignar la jerarquía a la propiedad PreferenceFragmentCompat.preferenceScreen

Plantilla Settings Activity En Android Studio

A pesar de que construimos manualmente nuestra actividad de ajustes junto al fragmento, puedes ahorrarte estos pasos de construcción con la plantilla Settings Activity.

Plantilla Settings Activity en Android Studio

Úsala desde la creación de un nuevo proyecto o desde New>Activity>Settings Activity.

Android Studio generará la actividad, el fragmento y el recurso XML con una jerarquía de ejemplo.

Plantilla Settings Activity en Android Studio

Tipos De Preferencias

En este tutorial viste el primer paso para crear tu pantalla de preferencias: crear el PreferenceFragmentCompat. Aprendiste a cómo crear la jerarquía de preferencias e inflarla. Además de obtener las preferencias desde el código para modificar sus atributos y procesar acciones de click.

No obstante, este ejemplo es muy básico en el estado en que está. Avanza al siguiente tutorial Tipos De Preferencias (todo) donde verás las diferentes clases que existen para representar diferentes patrones como la selección única, selección múltiple, diálogos, etc.


Más Contenidos Android

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!