Reputation: 85
Currently I'm trying to find an easy way to implement a step progress bar with compose like this:
Does anyone have experience with that? Is there maybe a good library?
Upvotes: 1
Views: 6912
Reputation: 496
Stepped progress bar with android compose
My requirement was slightly different from the actual question so i have update the code based on answers from other folks.
Thank You everyone for the help, here is the updated code
@Composable
fun StepsProgressBar(modifier: Modifier = Modifier, numberOfSteps: Int, currentStep: Int, color: Color) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
for (step in 0..numberOfSteps) {
Step(
modifier = Modifier.weight(1F),
isCompete = step < currentStep,
isLast = step == numberOfSteps,
isPending = currentStep - step == 1,
stepColor = color
)
}
}
}
@Composable
fun Step(modifier: Modifier = Modifier, isCompete: Boolean, isLast: Boolean, isPending: Boolean, stepColor: Color) {
val color: Color = if (isCompete) stepColor else colorResource(id = R.color.Gray300)
val sColor: Color = if (!isPending && isCompete) stepColor else colorResource(id = R.color.Gray300)
Box(modifier = modifier) {
if (!isLast) {
//Line
HorizontalDivider(
modifier = Modifier.align(Alignment.Center),
color = color,
thickness = 4.dp
)
}
//Circle
Canvas(modifier = Modifier
.size(12.dp)
.align(Alignment.CenterStart),
onDraw = {
drawCircle(color = color)
}
)
}
if (!isLast) {
Box(modifier = modifier) {
//Line
HorizontalDivider(
modifier = Modifier.align(Alignment.CenterEnd).background(
Brush.horizontalGradient(
startX = 0f,
endX = 25f,
colors = listOf(
color,
sColor
)
)),
color = Color.Transparent,
thickness = 4.dp
)
}
}
}
For @Preview() use like this
StepsProgressBar(modifier = Modifier.fillMaxWidth(), numberOfSteps = 5, currentStep = 3, color = Color.Red)
In case if you want to use it in XML based UI
<androidx.compose.ui.platform.ComposeView
android:id="@+id/progress_view"
android:layout_width="match_parent"
android:layout_height="12dp"/>
findViewById<ComposeView>(R.id.progress_view).setContent {
MaterialTheme {
Surface {
StepsProgressBar(
modifier = Modifier.fillMaxWidth(),
numberOfSteps = 5,
currentStep = 3
),
color = colorResource(
id = R.color.Primary
)
}
}
}
Output:
Upvotes: 0
Reputation: 236
Add jitpack in your build.gradle:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add compose-stepper library to your app/build.gradle
dependencies {
implementation 'com.github.maryamrzdh:compose-stepper:1.0.0-beta01'
}
Add a Stepper in a composable function
@Composable
fun StepperView() {
val numberOfSteps = 4
var currentStep by rememberSaveable { mutableStateOf(1) }
val titleList= arrayListOf("Step 1","Step 2","Step 3","Step 4")
Stepper(
modifier = Modifier.fillMaxWidth(),
numberOfSteps = numberOfSteps,
currentStep = currentStep,
stepDescriptionList = titleList,
unSelectedColor= Color.LightGray,
selectedColor = Color.Blue,
isRainbow = false
)
For more info go to Stepper using JetPack Compose
Upvotes: 0
Reputation: 214
I have created a similar function that takes customisable params.
@Composable
fun Track(
items: Int,
brush: (from: Int) -> Brush,
modifier: Modifier = Modifier,
lineWidth: Dp = 1.dp,
pathEffect: ((from: Int) -> PathEffect?)? = null,
icon: @Composable (index: Int) -> Unit,
) {
Box(
modifier = modifier,
contentAlignment = Alignment.Center,
) {
Canvas(
modifier = Modifier
.fillMaxWidth()
.zIndex(-1f)
) {
val width = drawContext.size.width
val height = drawContext.size.height
val yOffset = height / 2
val itemWidth = width / items
var startOffset = itemWidth / 2
var endOffset = startOffset
val barWidth = lineWidth.toPx()
repeat(items - 1) {
endOffset += itemWidth
drawLine(
brush = brush.invoke(it),
start = Offset(startOffset, yOffset),
end = Offset(endOffset, yOffset),
strokeWidth = barWidth,
pathEffect = pathEffect?.invoke(it)
)
startOffset = endOffset
}
}
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically,
) {
repeat(items) { index ->
Box(
contentAlignment = Alignment.Center,
) {
icon.invoke(index)
}
}
}
}
}
Upvotes: 1
Reputation: 362
I don't think you need a library from this one, a simple and quick 'do it yourself' solution could be something like this:
@Composable
fun StepsProgressBar(modifier: Modifier = Modifier, numberOfSteps: Int, currentStep: Int) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically
) {
for (step in 0..numberOfSteps) {
Step(
modifier = Modifier.weight(1F),
isCompete = step < currentStep,
isCurrent = step == currentStep
)
}
}
}
@Composable
fun Step(modifier: Modifier = Modifier, isCompete: Boolean, isCurrent: Boolean) {
val color = if (isCompete || isCurrent) Color.Red else Color.LightGray
val innerCircleColor = if (isCompete) Color.Red else Color.LightGray
Box(modifier = modifier) {
//Line
Divider(
modifier = Modifier.align(Alignment.CenterStart),
color = color,
thickness = 2.dp
)
//Circle
Canvas(modifier = Modifier
.size(15.dp)
.align(Alignment.CenterEnd)
.border(
shape = CircleShape,
width = 2.dp,
color = color
),
onDraw = {
drawCircle(color = innerCircleColor)
}
)
}
}
@Preview
@Composable
fun StepsProgressBarPreview() {
val currentStep = remember { mutableStateOf(1) }
StepsProgressBar(modifier = Modifier.fillMaxWidth(), numberOfSteps = 5, currentStep = currentStep.value)
}
This will be the result:
Upvotes: 14