ProgressBar En Android

La ProgressBar en Android es un widget para mostrar al usuario que se ha iniciado una tarea y será completa en un tiempo indefinido; o si es posible, proyectar la duración de una operación.

Representación visual de ProgressBar En Android

Usa este view para representar estados de tu aplicativo en los que el usuario comprenda que hay un proceso ejecutándose. Procesos como: peticiones web, búsquedas, procesamiento de archivos, sincronizaciones, carga de imágenes, etc.

A lo largo de este tutorial usaremos la siguiente aplicación Android de ejemplo. Esta consiste de una actividad simple que muestra el funcionamiento de la ProgressBar en variantes asociadas a su progreso (determinado e indeterminado) y tipo de indicador (lineal o circular):

App de ejemplo ProgressBar En Android

Puedes descargar el código fuente del proyecto Android Studio desde el siguiente enlace:

Atributos De ProgressBar En Android

La siguiente es una tabla con algunos de los atributos XML de ProgressBar para el manejo de la proyección del progreso que usaremos en este tutorial:

AtributoDescripción
android:indeterminatePermite habilitar el modo progreso indeterminado
android:indeterminateDrawableDrawable usado para el modo indeterminado
android:maxValor máximo del progreso
android:minValor mínimo del progreso
android:progressDetermina el valor por defecto del progreso. Es un valor entre 0 y max
android:secondaryProgressDefine el valor del progreso secundario (de 0 a max)

Veamos como crear comportamientos básicos a través de la variación de estos elementos.

Tipos De Indicadores

Hay dos estilos visuales para presentar la ProgressBar en pantalla: el indicador lineal y el circular. Ambos pueden ser usado a lo largo de tu app, pero evita usar ambos para representar un mismo tipo de actividad.

Indicador Lineal

El indicador lineal es dibujado como una barra horizontal que avanza en una pista, cuyo ancho representa el progreso máximo.

Ejemplo ProgressBar horizontal en Android

Para crear una ProgressBar con indicador horizontal desde Android Studio, abre la pestaña de diseño de tu layout y ve a Palette>Widgets>ProgressBar (Horizontal):

Desde XML añade la etiqueta <ProgressBar> y asignale al atributo style el estilo Widget.ProgressBar.Horizontal o la referencia equivalente progressBarStyleHorizontal:

<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="200dp"
    tools:progress="50"
    android:layout_height="wrap_content" />

Indicador Circular

El indicador circular es el estilo por defecto al añadir una barra de progreso, por lo que no tienes que hacer nada más para configurarlo.

ProgressBar circular en Android

Para añadirlo al layout usa uno de los estilos para los indicadores circulares:

<ProgressBar
    android:id="@+id/indeterminate_circular_indicator"
    style="?android:attr/progressBarStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Existe tres tamaños para el view de indicador circular:

  • ?android:attr/progressBarStyleSmall
  • ?android:attr/progressBarStyle
  • ?android:attr/progressBarStyleLarge

ProgressBar Con Progreso Indeterminado

Si desconoces el tiempo que tomará la realización de una acción usa el modo indeterminado de la ProgressBar. El indicador se animará de tal forma que el indicador crecerá y se acortará constantemente.

El atributo android:indeterminate es quien determina si la barra tendrá progreso indeterminado. En el indicador circular el por defecto es true, pero para el lineal es false, por lo que debes activarlo si requieres el progreso indeterminado.

<ProgressBar
    android:id="@+id/indeterminate_linear_indicator"
    style="?android:attr/progressBarStyleHorizontal"
    android:minHeight="24dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:indeterminate="true"/>

ProgressBar Con Progreso Determinado

En el caso de que conozcas de antemano la tasa de avance y el punto final de un proceso, entonces es preciso usar una barra de progreso determinada.

Solo la ProgressBar con indicador lineal puede tener progreso determinado. Puedes usar el atributo tools:progress para mostrar una guía del progreso en la previa del layout.

<ProgressBar
    android:id="@+id/determinate_linear_indicator"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:progress="70" />

Podemos simular la acumulación de progreso de la ProgressBar a través de una corrutina que perciba incrementos de cinco unidades cada segundo y actualizando el porcentaje en la vista:

class MainActivity : AppCompatActivity() {
    private val scope = MainScope()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val linearIndicator: ProgressBar = findViewById(R.id.determinate_linear_indicator)

        // Indicar determinado
        scope.launch {
            while (true)
                progress(linearIndicator)
        }        
    }

    private suspend fun progress(progressBar: ProgressBar) {
        while (progressBar.progress < progressBar.max) {
            delay(300)
            progressBar.incrementProgressBy(PROGRESS_INCREMENT)
        }
        progressBar.progress = 0
    }    

    override fun onDestroy() {
        super.onDestroy()
        scope.cancel() // Destruimos el alcance de la corrutina
    }

    companion object {
        const val PROGRESS_INCREMENT = 5
    }
}

En el código anterior, la primera instrucción es obtener al referencia de la ProgressBar en la variable linearIndicator. Luego lanzamos una corrutina donde invocamos un bucle while infinito con la ejecución del método progress().

progress() ejecuta otro while, donde la condición de salida es que el progreso actual sea menor que el valor máximo. Mientras itera, retardamos la corrutina por 300 milisegundos y luego retomamos con el incremento del progreso con incrementProgressBy().

Nota: Si deseas usar un indicador circular con progreso determinado, échale un vistazo a la clase CircularIndicatorProgress (todo).

De Indeterminado A Determinado

También es posible tener una ProgressBar que primero hace seguimiento en modo indeterminado y luego, al completarse, muestra un progreso determinado.

Cambiar ProgressBar de modo indeterminado a determinado

Para simular este comportamiento, permitimos que el modo indeterminado dure dos segundos y luego asignamos false a isIndeterminate.

Luego invocamos al método progress() para generar el progreso y terminamos modificando de nuevo a isIndeterminate hacia true:

override fun onCreate(savedInstanceState: Bundle?) {

    val indeterminateSwitch: ProgressBar = findViewById(R.id.indeterminate_to_determinate)

    // De indeterminado a determinado
    scope.launch {
        while (true)
            indeterminateToDeterminate(indeterminateSwitch)
    }   
}

private suspend fun indeterminateToDeterminate(
    progressBar: ProgressBar
) {
    delay(2000)
    progressBar.isIndeterminate = false
    progress(progressBar)
    progressBar.isIndeterminate = true
}

Segundo Indicador De Progreso

La clase ProgressBar permite representar el almacenamiento de información en un buffer, a través de un segundo indicador de progreso.

secondaryProgress en ProgressBar

Para cambiar su porcentaje usa el atributo android:secondaryProgress o el método setSecondaryProgress():

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)    
    
    val bufferProgressBar: ProgressBar = findViewById(R.id.buffer_progressbar)

    // Buffer
    scope.launch {
        while (true) {
            val async1 = scope.async {
                progress(bufferProgressBar)
            }
            val async2 = scope.async {
                secondaryProgress(bufferProgressBar)
            }
            async1.await()
            async2.await()
        }
    }
}

private suspend fun secondaryProgress(progressBar: ProgressBar) {
    while (progressBar.secondaryProgress < progressBar.max) {
        delay(150)
        progressBar.incrementSecondaryProgressBy(PROGRESS_INCREMENT)
    }
}

En este caso construimos dos corrutinas con la función async(), de tal forma que podamos esperar hasta que ambos elementos terminen el incremento de progresos. Claro está, usamos await() para coordinar la concurrencia al final del while().

Análogamente, usamos la función incrementSecondaryProgressBy() para incrementar el progreso secundario en secondaryProgress(). Como deseamos proyectar que el buffer está cargando datos en memoria más rápido que el uso de los mismos, entonces aplicamos un delay() con 150 milisegundos. Valor inferior al de progress().

Cambiar Color Del Indicador De Progreso

Usa el atributo android:indeterminateTint para cambiar el color del indicador indeterminado si tu nivel mínimo de SDK es 21 (Android Lollipop).

android:indeterminateTint="@color/blue"

Si no es así, Android Studio te mostrará una alerta de su incompatabilidad de uso con versiones anteriores. En ese caso usamos un cambio de tinte a través de la clase DrawableCompat y el método setTint():

DrawableCompat.setTint(
    blueProgressBar.indeterminateDrawable,
    ContextCompat.getColor(this, R.color.blue)
)
DrawableCompat.setTint(
    redProgressBar.indeterminateDrawable,
    ContextCompat.getColor(this, R.color.red)
)

En el ejemplo anterior aplicamos los colores Azul 500 y Rojo 500 de la tabla de Material Design sobre el atributo indeterminateDrawable. El resultado modificará a la barra de progresó de la siguiente forma:

Cambiar color de ProgressBar en 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!