In modern Android development using Jetpack Compose, providing feedback to users about ongoing processes is crucial for a good user experience. Progress indicators, such as loading bars and spinners, play a vital role in indicating that an application is actively working. Jetpack Compose simplifies the implementation of these indicators with its declarative syntax and built-in composables.
What are Progress Indicators?
Progress indicators are visual elements used to inform users that a process is underway. These indicators can be either determinate, showing the actual progress, or indeterminate, showing that a process is happening without indicating its specific state. Common types include circular and linear progress indicators.
Why Use Progress Indicators?
- Enhance user experience by providing feedback on ongoing processes.
- Prevent users from perceiving the application as unresponsive.
- Reduce user frustration by indicating that an action is being processed.
How to Implement Progress Indicators in Jetpack Compose
Jetpack Compose provides two primary types of progress indicators:
CircularProgressIndicator
: Shows progress in a circular form.LinearProgressIndicator
: Shows progress in a linear (horizontal) form.
1. CircularProgressIndicator
The CircularProgressIndicator
composable displays progress as a circle. It can be used in both determinate and indeterminate modes.
Indeterminate CircularProgressIndicator
An indeterminate CircularProgressIndicator
displays an animation to show that an operation is in progress without providing specific progress information. It is commonly used when the duration of the operation is unknown.
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun IndeterminateCircularProgressIndicatorExample() {
CircularProgressIndicator()
}
@Preview(showBackground = true)
@Composable
fun IndeterminateCircularProgressIndicatorPreview() {
IndeterminateCircularProgressIndicatorExample()
}
Determinate CircularProgressIndicator
A determinate CircularProgressIndicator
shows the progress of a specific task by filling the circle proportionally. This requires a progress
value between 0.0 and 1.0.
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun DeterminateCircularProgressIndicatorExample() {
var progress by remember { mutableStateOf(0.5f) }
CircularProgressIndicator(progress = progress)
}
@Preview(showBackground = true)
@Composable
fun DeterminateCircularProgressIndicatorPreview() {
DeterminateCircularProgressIndicatorExample()
}
2. LinearProgressIndicator
The LinearProgressIndicator
composable displays progress as a horizontal line. Like the circular indicator, it can be determinate or indeterminate.
Indeterminate LinearProgressIndicator
An indeterminate LinearProgressIndicator
displays a moving line to show that an operation is in progress without providing specific progress information.
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun IndeterminateLinearProgressIndicatorExample() {
LinearProgressIndicator()
}
@Preview(showBackground = true)
@Composable
fun IndeterminateLinearProgressIndicatorPreview() {
IndeterminateLinearProgressIndicatorExample()
}
Determinate LinearProgressIndicator
A determinate LinearProgressIndicator
shows the progress of a specific task by filling the line proportionally. This requires a progress
value between 0.0 and 1.0.
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun DeterminateLinearProgressIndicatorExample() {
var progress by remember { mutableStateOf(0.5f) }
LinearProgressIndicator(progress = progress)
}
@Preview(showBackground = true)
@Composable
fun DeterminateLinearProgressIndicatorPreview() {
DeterminateLinearProgressIndicatorExample()
}
Customizing Progress Indicators
Jetpack Compose allows you to customize progress indicators with various parameters such as color, stroke width, and size.
Customizing CircularProgressIndicator
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun CustomCircularProgressIndicatorExample() {
CircularProgressIndicator(
color = MaterialTheme.colorScheme.secondary,
strokeWidth = 5.dp
)
}
@Preview(showBackground = true)
@Composable
fun CustomCircularProgressIndicatorPreview() {
CustomCircularProgressIndicatorExample()
}
Customizing LinearProgressIndicator
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun CustomLinearProgressIndicatorExample() {
LinearProgressIndicator(
color = MaterialTheme.colorScheme.tertiary,
backgroundColor = Color.LightGray
)
}
@Preview(showBackground = true)
@Composable
fun CustomLinearProgressIndicatorPreview() {
CustomLinearProgressIndicatorExample()
}
Implementing Progress Indicators with State Management
To effectively use progress indicators, integrate them with your application’s state. Use remember
and mutableStateOf
to manage the loading state.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Composable
fun LoadingButtonExample() {
var loading by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
Button(
onClick = {
loading = true
scope.launch {
delay(3000) // Simulate loading
loading = false
}
},
enabled = !loading
) {
if (loading) {
Row(verticalAlignment = Alignment.CenterVertically) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
strokeWidth = 3.dp,
color = MaterialTheme.colorScheme.onPrimary
)
Spacer(modifier = Modifier.width(8.dp))
Text("Loading...")
}
} else {
Text("Load Data")
}
}
}
@Preview(showBackground = true)
@Composable
fun LoadingButtonPreview() {
LoadingButtonExample()
}
In this example:
- A button’s state changes to loading when clicked.
- While loading, a
CircularProgressIndicator
is displayed along with text. - The state is managed using
remember
andmutableStateOf
. - A
CoroutineScope
is used to simulate an asynchronous task withdelay
.
Conclusion
Progress indicators are crucial for providing feedback and enhancing user experience in Android applications. Jetpack Compose simplifies their implementation with composables like CircularProgressIndicator
and LinearProgressIndicator
. By understanding how to use and customize these indicators, developers can create more engaging and user-friendly apps.