Create an animated Instagram-like progress bar with Jetpack Compose
source link: https://blog.bam.tech/developer-news/create-an-animated-instagram-like-progress-bar-with-jetpack-compose
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Jetpack Compose is the new and trending way to build Android UI.
At BAM, we use it on all new projects. On older projects, we make a plan to refactor good old XML to Composable.
This is the first post of a series of How to do this with Jetpack Compose.
Let’s go !
Recreating Instagram’s stories progress bar
Do you know Instagram stories ? They are a slideshow of full screen mobile pictures. Here is an example :
Instagram story (from @themonkeyuser)
We will try to recode the progress bar like this :
Our Jetpack Compose Stories !
Specs are :
- we are given a number of steps (number);
- we are given the current step index (number);
- we are given whether to pause the progression or not (boolean);
- we would like to be able to do something when we reach the end of a step (a callback);
The layout of one progress bar
We will use a Row
with a background for the progress bar background.
And a Box
for the progress bar foreground.
@Preview(widthDp = 200)
@Composable
fun ProgressBarPreview() {
Row(
modifier = Modifier
.height(4.dp)
.clip(RoundedCornerShape(50, 50, 50, 50)) // (1)
.background(Color.White.copy(alpha = 0.4f)) // (2)
) {
Box(
modifier = Modifier
.background(Color.White)
.fillMaxHeight()
.fillMaxWidth(0.5f), // (3)
) {}
}
}
- Creates rounded corner. Order of
Modifier
is important. Here,clip
is applied on top ofbackground
. - Adds the white translucent background.
- Fill a percentage of the width.
Result :
The layout of multiple progress bar
We need to iterate over an index.
@Preview(widthDp = 600)
@Composable
fun InstagramSlicedProgressBar(
steps: Int = 3,
currentStep: Int = 2
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.height(48.dp)
.padding(24.dp, 0.dp),
) {
for (index in 1..steps) { // (1)
// We use our previous code :
Row(
...
) {
Box(
modifier = Modifier
...
.fillMaxHeight().let {
// Here we check if we need to fill the progress bar of not :
when (index) { // (2)
currentStep -> it.fillMaxWidth(.5f)
in 0..currentStep -> it.fillMaxWidth(1f)
else -> it
}
},
) {}
}
if (index != steps) {
Spacer(modifier = Modifier.width(4.dp)) // (3)
}
}
}
}
- We iterate over a range from 1 to the given steps number.
- Before current step, we fill the progress bar; at the current step, we fill a fraction; after, we do nothing.
- We insert a
Spacer
between each progress bar.
Result :
Animation and pause
We will need a LaunchedEffect
:
@Preview(widthDp = 600)
@Composable
fun InstagramSlicedProgressBar(
steps: Int = 3,
currentStep: Int = 2,
paused: Boolean = false,
onFinished: () -> Unit = {}
) {
val percent = remember { Animatable(0f) } // (1)
LaunchedEffect(paused) { // (2)
if (paused) percent.stop()
else {
percent.animateTo(
targetValue = 1f,
animationSpec = tween(
durationMillis = (5000 * (1f - percent.value)).toInt(), // (3)
easing = LinearEasing
)
)
onFinished() // (4)
}
}
Row(...) {
for (...) {
Row(...) {
Box(
modifier = Modifier
...
.fillMaxHeight().let {
when (index) {
currentStep -> it.fillMaxWidth(percent.value) // (5)
...
}
},
) {}
}
...
}
}
}
- Creates an animated value that the composable will remember across recompositions.
- Every time
paused
changes, launch the effect in a coroutine. - Animate from the current value to 100% with the following spec.It should take 5 seconds to go from 0 to 100%
- Calls the
onFinished
callback once animation is done. - Use our animated value current value to fill current step.
Tadaaa 🎉
We are done with our progress bar !
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK