Icono del sitio Develou

SeekBar En Android

La SeekBar En Android es una subclase de la ProgressBar que extiende sus funcionalidades para agregar un control deslizante en la pista del indicador.

Su objetivo es permitirte elegir un único valor de un rango de valores conocidos previamente. Esto puedes verlo en casos de uso como: ajustes de preferencias (volumen, brillo, alpha, etc.), filtros de características de items, control temporal de reproductores de música y video, etc.

A lo largo de este tutorial usaremos la siguiente App de ejemplo para interiorizar el conocimiento sobre la SeekBar. Se trata de la inclusión de dos variaciones del view para procesar eventos de cambios del deslizador, cambio del color y cambio del drawable del deslizador:

Descarga el código del proyecto Android Studio desde el siguiente enlace:

Atributos De SeekBar En Android

SeekBar es descendiente de AbsSeekBar, que a su vez es descendiente de ProgressBar. Por esta razón, podrás acceder a los atributos para el manejo de progreso sin problemas.

Para soportar al deslizador, se agregaron los siguientes elementos:

Atributo XMLDescripción
android:thumbEs el drawable para proyectar al deslizador (pulgar o perilla)
android:thumbTintTinte que se aplica a thumb
android:tickMarkTintTinte que se aplica al drawable de las graduaciones sobre el indicador

Ahora veamos como modificar estos y otros atributos para cambiar la presentación de la SeekBar.

Crear SeekBar

Supongamos que necesitamos crear una SeekBar con un rango de valores entre 0 y 60 y un progreso por defecto en 45:

Para añadir una SeekBar en Android Studio ve a Palette>Widgets>SeekBar y arrastra el componente al lienzo o al Component Tree:

La creación en XML que satisface la configuración se representaría con la etiqueta <SeekBar> y la modificación de los atriabutos android:max y android:progress:

<SeekBar
    android:id="@+id/seekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="60"
    android:progress="45" />

También podemos hacerlo programáticamente. Asumiendo que su padre sea un ConstraintLayout (todo), crear la SeekBar en Kotlin se vería así:

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

        val parent: ConstraintLayout = findViewById(R.id.constraint_layout)
        val seekbar = SeekBar(this).apply {
            id = ViewCompat.generateViewId()
            max = 60
            progress = 45
            layoutParams = LayoutParams(0, WRAP_CONTENT)
        }

        parent.addView(seekbar)

        with(ConstraintSet()) {
            clone(parent)
            connect(seekbar.id, TOP, PARENT_ID, TOP)
            connect(seekbar.id, RIGHT, PARENT_ID, RIGHT)
            connect(seekbar.id, LEFT, PARENT_ID, LEFT)
            applyTo(parent)
        }
    }
}

Nos valemos de la función apply() para contextualizar la inicialización del objeto SeekBar. Luego añadimos la barra al constraint layout y finalmente conectamos sus limites a través de with() para mejorar la legibilidad de invocaciones.

SeekBar Discreta

Existe un estilo que añade graduaciones sobre el indicador lineal de la SeekBar. Estas son representadas por marcas uniformes a lo largo de la pista de selección:

A esta representación se le denomina SeekBar discreta y facilitan la selección exacta de un valor del rango. Para implementarla solo usa el estilo Widget.AppCompat.SeekBar.Discrete:

<SeekBar
    android:id="@+id/discrete_seekbar"
    style="@style/Widget.AppCompat.SeekBar.Discrete"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="5"
    android:progress="3" />

Cada punto de graduación representará a la unidad, por lo que seteas a max muy alto se mostrará atosigado el indicador. Por lo que la SeekBar discreta funciona mejor con pequeños conjuntos de valores preestablecidos.

Observar Cambios De La SeekBar

En nuestra app de ejemplo usamos el evento de cambio de progreso para actualizar el texto asociado a las SeekBars:

Lograr esta detección de cambios se consigue usando a la escucha OnSeekBarChangeListener. Esta nos provee los siguientes controladores:

En el caso de la SeekBar que hace seguimiento a la transparencia de la letra D, implementamos a onProgressChanged() para actualizar al cambiar el progreso:

continuousSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
        letter.alpha = progress/60f
    }

    override fun onStartTrackingTouch(seekBar: SeekBar?) {

    }

    override fun onStopTrackingTouch(seekBar: SeekBar?) {

    }

})

Y por el lado de la seekbar discreta que actualiza el texto dependiendo de la temperatura, implementamos a onStopTrackingTouch():

discreteSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {

    }

    override fun onStartTrackingTouch(seekBar: SeekBar?) {

    }

    override fun onStopTrackingTouch(seekBar: SeekBar?) {
        seekBar?.apply {
            tempLevel.text = when (progress) {
                0 -> "Glacial"
                1 -> "Páramo"
                2 -> "Frío"
                3 -> "Templado"
                4 -> "Cálido"
                else -> "Desconocido"
            }
        }
    }

})

Debido a que el argumento seekBar es anulable, usamos al operador de acceso seguro ?, seguido de la invocación de apply() para setear a text el resultado de la expresión when.

Cambiar Color Del Deslizador

De repente queremos que los drawables del thumb, el progreso y la pista se proyecten con escalas de rojo:

Para modificar estos colores modificamos los valores de android:thumb, android:progressTint y android:progressBackgroundTint:

<SeekBar
    android:id="@+id/continuous_seekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="60"
    android:thumbTint="@color/red_700"
    android:progressTint="@color/red_500"
    android:progressBackgroundTint="@color/red_700"
    android:progress="45" />

No obstante, estos requieren el uso de un nivel mínimo de API en 21. Si no cumples con estas condiciones, lo mejor es colorearlos desde el código con la clase DrawableCompat:

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

        val continuousSeekBar: SeekBar = findViewById(R.id.continuous_seekbar)
        continuousSeekBar.apply {
            tintDrawable(thumb, R.color.red_700)
            tintDrawable(progressDrawable, R.color.red_500)
        }           
    }

    private fun tintDrawable(drawable: Drawable, @ColorRes color:Int){
        DrawableCompat.setTint(
            drawable,
            ContextCompat.getColor(this, color)
        )
    }
}

Cambiar Drawable Del Thumb

En la seekbar discreta que hace seguimiento a niveles de temperatura modificamos el drawable del deslizador por un vector de termostato:

Reemplazar el drawable requiere la asignación del atributo android:thumb por el recurso que necesites en tu etiqueta <SeekBar>:

<SeekBar
    android:id="@+id/discrete_seekbar"
    style="@style/Widget.AppCompat.SeekBar.Discrete"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="4"
    android:splitTrack="false"
    android:thumb="@drawable/ic_temp_thumb"
    android:progress="3"/>

Recuerda que puedes presionar click derecho en el directorio res/drawable y seleccionar la opción New > Vector Asset para agregar vectores. Ahí encontrarás una miscelánea con gran variedad de elementos. En este caso nosotros usamos el vector con nombre «thermostat»:

En versiones previas a Android Lollipop el deslizador se camufla con transparencia en la pista de la SeekBar, pero para habilitar este efecto en versiones posteriores, usa android:splitTrack en false.

Salir de la versión móvil