Is there a way to align a item on the bottom of a LazyColumn?

Viewed 2281

I'm trying to implement a list with a button on its bottom, like the following:

enter image description here

Since I don't know how many items I would have on the list, I'm using a LazyColumn. The button on the bottom, should only be placed there if the list doesn't fill the entire screen, if it does, the button should be moved down and be the last item on the list.

Moving the button inside the LazyColumn like this:

LazyColumn(...) {
    items(items) { item -> ...}
    item { Button() } 
}

Gives the following:

enter image description here

I tried to add a Spacer with fillMaxHeight() modifier as an item between the two but it didn't change.

I also tried to add both the LazyColumn and the Button inside a column:

Column {
   LazyColumn(
        modifier = Modifier.weight(1f)
   ) {
        items(items) { item -> ...}
   }
   Button()
}

But this only anchors the button on the bottom as if the Column was a LinearLayout.

Considering this, would it be possible to align one of the LazyColumn's items so it will always be on the bottom? Or, add some kind of space that fill the available area?

2 Answers

As stated in this closed issue it's possible to use LazyColumn's verticalArrangement parameter to align the last item on the bottom by implementing Arrangement.Vertical:

LazyColumn(verticalArrangement = remember {
    object : Arrangement.Vertical {
        override fun Density.arrange(
            totalSize: Int,
            sizes: IntArray,
            outPositions: IntArray
        ) {
            var currentOffset = 0
            sizes.forEachIndexed { index, size -> 
                if (index == sizes.lastIndex) {
                    outPositions[index] = totalSize - size
                } else {
                    outPositions[index] = currentOffset
                    currentOffset += size
                }
            }
        }
    }
})

If you want to use it with spacedBy on the verticalArrangement parameter, as I was, you could use the following:

fun spacedByWithFooter(space: Dp) = object : Arrangement.Vertical {

    override val spacing = space

    override fun Density.arrange(
        totalSize: Int,
        sizes: IntArray,
        outPositions: IntArray,
    ) {
        if (sizes.isEmpty()) return
        val spacePx = space.roundToPx()

        var occupied = 0
        var lastSpace = 0

        sizes.forEachIndexed { index, size ->

            if (index == sizes.lastIndex) {
                outPositions[index] = totalSize - size
            } else {
                outPositions[index] = min(occupied, totalSize - size)
            }
            lastSpace = min(spacePx, totalSize - outPositions[index] - size)
            occupied = outPositions[index] + size + lastSpace
        }
        occupied -= lastSpace
    }
}

We can wrap the button and LazyColumn with Column like this and ues verticalArrangement SpaceBetween.

we also can replace SpaceBetween with SpaceAround

   Column(
    modifier = Modifier.fillMaxSize(),
    verticalArrangement = Arrangement.SpaceBetween
) {
    LazyColumn(...) {

        items(items) { item -> ... }
    }
    Button()
}

I hope that has helped you.

Related