Search code examples
androidandroid-jetpack-composeandroid-jetpack-compose-list

Jetpack Compose - Make the first element in a LazyRow be aligned to the center of the screen


I want to obtain a LazyRow that looks like this:

|--aaa-b|bb-cccc|-dd... ...|w--x---|

|-------| is one screen width

The size of the elements varies but they have a fixed spacing between them. I thought I could add some start content padding to the LazyRow so that the "aaa" Composable is aligned to the center of the screen, but I don't know its width.

If you think it's not clear what I'm asking, please drop a comment.

UPDATE

Added a gif for better understanding

enter image description here


Solution

  • You can use the BoxWithConstraints to get screen width. Then you can use Layout to properly positioning the item in the list.

    @Composable
    fun BigCarousel() {
        val items = (0..10).map { "Item $it" }
        BoxWithConstraints {
            LazyRow {
                itemsIndexed(items) { index, item ->
                    Layout(
                        content = {
                            // Here's the content of each list item.
                            Box(
                                Modifier
                                    .size(200.dp)
                                    .padding(8.dp)
                                    .background(Color.Gray)
                            ) {
                                Text(text = item, Modifier.align(Alignment.Center))
                            }
                        },
                        measurePolicy = { measurables, constraints ->
                            // I'm assuming you'll declaring just one root 
                            // composable in the content function above
                            // so it's measuring just the Box
                            val placeable = measurables.first().measure(constraints)
                            // maxWidth is from the BoxWithConstraints
                            val maxWidthInPx = maxWidth.roundToPx()
                            // Box width
                            val itemWidth = placeable.width
                            // Calculating the space for the first and last item
                            val startSpace =
                                if (index == 0) (maxWidthInPx - itemWidth) / 2 else 0
                            val endSpace =
                                if (index == items.lastIndex) (maxWidthInPx - itemWidth) / 2 else 0
                            // The width of the box + extra space
                            val width = startSpace + placeable.width + endSpace
                            layout(width, placeable.height) {
                                // Placing the Box in the right X position
                                val x = if (index == 0) startSpace else 0
                                placeable.place(x, 0)
                            }
                        }
                    )
                }
            }
        }
    }
    

    Here's the result:

    enter image description here