androidkotlinandroid-jetpack-compose

Spacing views inside a compose row so the last view always is half shown


I have a compose card and inside a row with circle views, I need to make it so the last item in this row is half shown only. Is there a easy way to achieve this without measuring the screen width after everything is drawn and then modify the padding for the row items dynamically to achieve it?)

enter image description here


Solution

  • If you need to calculate the number of elements depending on the size of the cell contents, it is impossible to do this without real measurements.

    But if you know exactly how many elements you need to display, you can use Modifier.fillParentMaxWidth with the desired fraction. This is only available in lazy views like LazyRow.

    Things are a bit more complicated with spacings: usually contentPadding is used to offset the first element, which reduces the parent size, depending on which Modifier.fillParentPaxMaxWidth calculates the actual value. Also, if you apply it to both start and end, you won't get the desired result. That's why I apply it only to start, and create an equivalent effect at the end with another item.

    I also manually surround the Spacers item instead of using Arrangement.spacedBy, because the spacers should be inside the Modifier.fillParentMaxWidth too.

    val spacing = 20.dp
    val halfSpacing = spacing / 2
    val shape = RoundedCornerShape(20)
    LazyRow(
        contentPadding = PaddingValues(start = halfSpacing),
        modifier = Modifier
            .padding(30.dp)
            .border(1.dp, color = Color.Black, shape = shape)
            .clip(shape)
            .padding(vertical = 20.dp)
    ) {
        items(10) {
            Row(
                Modifier
                    .fillParentMaxWidth(1f / 3.5f)
            ) {
                Spacer(Modifier.size(halfSpacing))
                Box(
                    Modifier
                        .weight(1f)
                        .aspectRatio(1f)
                        .background(Color.Blue, shape = CircleShape)
                )
                Spacer(Modifier.size(halfSpacing))
            }
        }
        item {
            Spacer(Modifier.size(halfSpacing))
        }
    }
    

    Result:

    LazyColumn variant:

    val spacing = 20.dp
    val halfSpacing = spacing / 2
    val shape = RoundedCornerShape(20)
    LazyColumn(
        contentPadding = PaddingValues(top = halfSpacing),
        modifier = Modifier
            .padding(30.dp)
            .border(1.dp, color = Color.Black, shape = shape)
            .clip(shape)
            .padding(horizontal = 20.dp)
    ) {
        items(10) {
            Column(
                Modifier
                    .fillParentMaxHeight(1f / 3.5f)
            ) {
                Spacer(Modifier.size(halfSpacing))
                Box(
                    Modifier
                        .weight(1f)
                        .aspectRatio(1f)
                        .background(Color.Blue, shape = CircleShape)
                )
                Spacer(Modifier.size(halfSpacing))
            }
        }
        item {
            Spacer(Modifier.size(halfSpacing))
        }
    }