I want to achieve this using jetpack compose.

enter image description here

A is scrollable list of row items. When A is smaller than screen(or parent) size, B(footer) should be placed bellow the last row. When A + B are bigger than screen size, then B becomes fixed at the bottom and A content is scrollable. I'm wondering if there is easy way to achieve this, using compose ConstraintLayout.

4

There are 4 answers

0
Bpn On

The solution is to use Modifier.weight(1f, false) in A. This is because the parent element's size will first be used by unweighted elements and then the remaining space will be distributed to weighted elements according to their weights. See this answer for more details.

1
Puneet Verma On

There are many ways to do this but the most efficient way is to use the bottomBar property of Scaffold View.

For example:

@Composable
fun RenderContent() {
    Scaffold(
        topBar = { /* Your app bar goes here */ },
        bottomBar = { /* Anything you place in here will be stick to the bottom. */ }
    ) {
        // ... Rest of the content
        // Benefits: If you make the content scrollable and
        // the `bottomBar` composable remain on top of the content
    }
}
0
Jakub Kostka On

While most straight forward way would be the use of ConstraintLayout I can't recommend it, since there are currently too many bugs and it doesn't seem stable from my experience.

The simplest way outside of ConstraintLayout is using a any container element that draws children over eachother, such as Scaffold or Box. Since Scaffold holds too much logic for such a simple workaround, I'd go with Box every single time.

The simples example I can give is

Box {
    LazyColumn {
        stickyHeader {

        }
        items(listOf()) {
            
        }
    }

    // doesn't have to be a Box, any element will do, such as Row/Column/...
    // the Alignment.BottomCenter is the key
    Box(modifier = Modifier.align(Alignment.BottomCenter)) {
        //This is your sticky footer Content
    }
}

The only drawback I see is offset you have to provide to the LazyColumn in order to be "above" the footer. This can be achieved like this:

Box {
    LazyColumn {
        stickyHeader {

        }
        items(listOf()) {

        }
        item {
            Spacer(
                modifier = Modifier.height(
                    with(LocalDensity.current) {
                        stickyFooterHeight.intValue.toDp()
                    }
                )
            )
        }
    }

    Box(
        modifier = Modifier
            .align(Alignment.BottomCenter)
            .onSizeChanged {
                stickyFooterHeight.intValue = it.height
            }
    ) {
        //...
    }
}

Optionally, you can turn it into a component, which you can easily reuse again and add .animateContentSize on the Spacer to make it look seamless.

2
Worker123 On

If I understood you correctly you are trying to add a footer view to a LazyColmn. The LazyColumn in JetpackCompose is behaving like the native ListView. I will give an example of a LazyColumn that has a view(composable) at the bottom that is shown when you scroll at the end of the list:

LazyColumn() {
item {
    //If you want the first item to stay always on top as you scroll use stickyHeader for this section.
    Text("This is the first item")
}
items(listItems.size) {
    Text("This is a normal list item")
}
item {
    Text("This item will behave as a footer and display at the end of the list")
}

}

Hope this helps somebody. Thanks