Icono del sitio Develou

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.

Por lo que en este tutorial aprenderás a:


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):

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.

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:

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

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:

Los atributos base usados tienen el siguiente propósito:


5. Inflar Jerarquía De Preferencias

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

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.

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.

Ú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.


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

Salir de la versión móvil