Home > Software design >  How to Make LinearProgressIndicator Width Dynamic With Jetpack Compose
How to Make LinearProgressIndicator Width Dynamic With Jetpack Compose

Time:11-09

I'm trying to make the following layout using Compose:

enter image description here

The problem I'm having is that I can't make the width of the LinearProgressIndicator to be the same as the Text 1 composable's width. This is my implementation so far:

@Composable
fun ExampleCard(
    modifier: Modifier = Modifier
) {
    MaterialTheme {
        Surface(color = Color(0xFFFFFFFF)) {
            Card(
                elevation = 5.dp,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(10.dp)
            ) {
                Column(modifier = Modifier.padding(10.dp)) {
                    Text(
                        text = "Card Title",
                        fontWeight = FontWeight.Bold,
                        fontSize = 24.sp
                    )
                    Row {
                        Column(
                            modifier = Modifier
                                .width(IntrinsicSize.Min)
                                .padding(end = 5.dp)
                        ) {
                            Text("Text 1")
                            LinearProgressIndicator(
                                progress = 0.5f,
                                modifier = Modifier.fillMaxWidth()
                            )
                        }
                        Text(
                            text = "Text 2",
                            modifier = Modifier.weight(1f)
                        )
                    }
                }
            }
        }
    }
}

This is the result:

enter image description here

As you can see the LinearProgressIndicator takes as much width as it needs, making the parent Column wider than the Text 1 composable. The idea is that the LinearProgressIndicator should be as wide as Text 1 and as Text 1 expands so should LinearProgressIndicator. Notice that I'm using intrinsics as it seems to be the way to solve this issue but it's not working, which could be due to the fixed width that LinearProgressIndicator has by default:

@Composable
fun LinearProgressIndicator(
    ...
    modifier: Modifier = Modifier,
    ...
) {
    Canvas(
        modifier
            .progressSemantics(progress)
            .size(LinearIndicatorWidth, LinearIndicatorHeight)
            .focusable()
    ) {
        ...
    }
}

private val LinearIndicatorWidth = 240.dp

I'd like to know how can I make the width of the LinearProgressIndicator dynamic to accomplish that layout, which seems pretty straightforward but apparently I'm missing something.

CodePudding user response:

Even the maintainers aren't sure it's a good solution:

TODO: there are currently 3 fixed widths in Android, should this be flexible? Material says the width should be 240dp here.

I think you should create an issue to let them know you have an interest in such a feature.

In the meantime, you can get around it as follows:

SubcomposeLayout(Modifier.padding(end = 5.dp)) { constraints ->
    val textPlaceable = subcompose("Text") {
        Text("Text 1")
    }[0].measure(constraints)
    val progressIndicatorPlaceable = subcompose("ProgressIndicator") {
        LinearProgressIndicator(
            progress = 0.5f,
        )
    }[0].measure(constraints.copy(maxWidth = textPlaceable.width))
    layout(
        width = textPlaceable.width,
        height = textPlaceable.height   progressIndicatorPlaceable.height,
    ) {
        textPlaceable.place(0, 0)
        progressIndicatorPlaceable.place(0, textPlaceable.height)
    }
}
  • Related