Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose collapsing toolbar

I can't find any doc on the matter, is there something similar to a CollapsingToolbar in Compose?

All I found was a mention of it here, but nothing on how to set it up

like image 582
Merig Avatar asked Apr 23 '21 09:04

Merig


4 Answers

I found a solution created by Samir Basnet (from Kotlin Slack Channel) which was useful for me, I hope it helps someone else...

@Composable
fun CollapsingEffectScreen() {
    val items = (1..100).map { "Item $it" }
    val lazyListState = rememberLazyListState()
    var scrolledY = 0f
    var previousOffset = 0
    LazyColumn(
        Modifier.fillMaxSize(),
        lazyListState,
    ) {
        item {
            Image(
                painter = painterResource(id = R.drawable.recife),
                contentDescription = null,
                contentScale = ContentScale.FillWidth,
                modifier = Modifier
                    .graphicsLayer {
                        scrolledY += lazyListState.firstVisibleItemScrollOffset - previousOffset
                        translationY = scrolledY * 0.5f
                        previousOffset = lazyListState.firstVisibleItemScrollOffset
                    }
                    .height(240.dp)
                    .fillMaxWidth()
            )
        }
        items(items) {
            Text(
                text = it,
                Modifier
                    .background(Color.White)
                    .fillMaxWidth()
                    .padding(8.dp)
            )
        }
    }
}

Here is the result:

enter image description here

like image 126
nglauber Avatar answered Oct 07 '22 01:10

nglauber


Jetpack Compose implementation of Material Design 3 includes 4 types of Top App Bars (https://m3.material.io/components/top-app-bar/implementation):

  • CenterAlignedTopAppBar
  • SmallTopAppBar
  • MediumTopAppBar
  • LargeTopAppBar

https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary

They all have a scrollBehavior parameter, which can be used for collapsing the toolbar. There are 3 basic types of scroll behavior in the library:

  • TopAppBarDefaults.pinnedScrollBehavior
  • TopAppBarDefaults.enterAlwaysScrollBehavior
  • TopAppBarDefaults.exitUntilCollapsedScrollBehavior

https://developer.android.com/reference/kotlin/androidx/compose/material3/TopAppBarDefaults

Note: This API is annotated as experimental at the moment.

Sample usage:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Test() {
    val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            MediumTopAppBar(
                title = { Text(text = "Scroll Behavior Test") },
                navigationIcon = {
                    IconButton(onClick = { /*TODO*/ }) {
                        Icon(imageVector = Icons.Default.Menu, contentDescription = "")
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) {
        LazyColumn(modifier = Modifier.fillMaxWidth()) {
            items((1..50).toList()) { item ->
                Text(modifier = Modifier.padding(8.dp), text = "Item $item")
            }
        }
    }
}
like image 39
Manveru Avatar answered Oct 07 '22 00:10

Manveru


I found this in Android docs, I think the documentation you linked in the question is talking about doing it like this with nested scrolling.

val toolbarHeight = 48.dp
    val toolbarHeightPx = with(LocalDensity.current) { toolbarHeight.roundToPx().toFloat() }
    val toolbarOffsetHeightPx = remember { mutableStateOf(0f) }

    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {

                val delta = available.y
                val newOffset = toolbarOffsetHeightPx.value + delta
                toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f)
                return Offset.Zero
            }
        }
    }
    Box(
        Modifier
            .fillMaxSize()

            .nestedScroll(nestedScrollConnection)
    ) {

        LazyColumn(contentPadding = PaddingValues(top = toolbarHeight)) {
            items(100) { index ->
                Text("I'm item $index", modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp))
            }
        }
        TopAppBar(
            modifier = Modifier
                .height(toolbarHeight)
                .offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) },
            title = { Text("toolbar offset is ${toolbarOffsetHeightPx.value}") }
        )
    }
like image 10
SpiderGod607 Avatar answered Oct 07 '22 01:10

SpiderGod607


You can use the compose-collapsing-toolbar library.

Instalation : implementation "me.onebone:toolbar-compose:2.1.0"

Usage - Exemple

Preview

Here are some gif images from the Readme.md of the library:

jetpack compose collapsing toolbarjetpack compose collapsing toolbar | EnterAlwaysCollapsedjetpack compose collapsing toolbar | ExitUntilCollapsed

like image 6
sitatech Avatar answered Oct 07 '22 02:10

sitatech