coffeLord
coffeLord

Reputation: 85

step progress bar with android compose

Currently I'm trying to find an easy way to implement a step progress bar with compose like this:

enter image description here

Does anyone have experience with that? Is there maybe a good library?

Upvotes: 1

Views: 6912

Answers (4)

MadLeo
MadLeo

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:

enter image description here

Upvotes: 0

Maryam Memarzadeh
Maryam Memarzadeh

Reputation: 236

  1. Add jitpack in your build.gradle:

    allprojects {
        repositories {
        ...
        maven { url 'https://jitpack.io' }
      }
    }
    
  2. 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

Jagarapu Sahruday
Jagarapu Sahruday

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)
                }
            }
        }
    }
}

enter image description here

Upvotes: 1

42Geek
42Geek

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:

enter image description here

Upvotes: 14

Related Questions