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.
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):
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:
Atributo | Descripción |
---|---|
android:indeterminate | Permite habilitar el modo progreso indeterminado |
android:indeterminateDrawable | Drawable usado para el modo indeterminado |
android:max | Valor máximo del progreso |
android:min | Valor mínimo del progreso |
android:progress | Determina el valor por defecto del progreso. Es un valor entre 0 y max |
android:secondaryProgress | Define 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.
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.
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.
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.
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:
Ú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!