Question Details

No question body available.

Tags

android kotlin android-jetpack-compose

Answers (1)

Accepted Answer Available
Accepted Answer
September 10, 2025 Score: 1 Rep: 12,948 Quality: High Completeness: 80%

Edit:

If you want to modify the default collapsing animation, I would suggest that you implement the collapsing using a custom NestedScrollConnection. Please have a look at the following code:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomCollapsingToolbar() {

val localDensity = LocalDensity.current val statusBarDp = with(localDensity) { WindowInsets.statusBars.getTop(localDensity).toDp() } var maxToolbarHeightPx by remember(statusBarDp) { mutableFloatStateOf((TopAppBarDefaults.TopAppBarExpandedHeight + statusBarDp).dpToPx(localDensity)) } var currentToolbarHeightPx by remember(maxToolbarHeightPx) { mutableFloatStateOf(maxToolbarHeightPx) }

val nestedScrollConnection = remember(maxToolbarHeightPx) { object : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val delta = available.y val newHeaderHeightPx = currentToolbarHeightPx + delta currentToolbarHeightPx = newHeaderHeightPx.coerceIn(0f, maxToolbarHeightPx) val unconsumedPx = newHeaderHeightPx - currentToolbarHeightPx return Offset(x = 0f, y = delta - unconsumedPx) } } }

Scaffold( modifier = Modifier .fillMaxSize() .nestedScroll(nestedScrollConnection), contentWindowInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp), ) { scaffoldInnerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(scaffoldInnerPadding) .background(Color.Gray) ) { Box( modifier = Modifier .height(currentToolbarHeightPx.toInt().pxToDp(localDensity)) .wrapContentHeight(Alignment.Bottom, unbounded = true), ) { TopAppBar( title = { Text( modifier = Modifier.padding(top = statusBarDp), text = "My App" ) }, expandedHeight = TopAppBarDefaults.TopAppBarExpandedHeight + statusBarDp, modifier = Modifier.fillMaxWidth(), colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Red, titleContentColor = Color.White ), windowInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp) ) } LazyColumn( modifier = Modifier.weight(1f), contentPadding = PaddingValues(16.dp) ) { items(50) { index -> Text( "Item $index", modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp), color = Color.Black ) } } } } }

Output:

Screen Recording

Answer using default collapsing animation:

You can try to use a combination of expandedHeight together with WindowInsets.statusBars.getTop():

// enableEdgeToEdge()
// no other window options needed

val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) val localDensity = LocalDensity.current val statusBarDp = with(localDensity) { WindowInsets.statusBars.getTop(localDensity).toDp() }

Scaffold( modifier = Modifier .fillMaxSize() .nestedScroll(scrollBehavior.nestedScrollConnection), // contentWindowInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp), topBar = { TopAppBar( title = { Text( modifier = Modifier.padding(top = statusBarDp), text = "My App" ) }, expandedHeight = TopAppBarDefaults.TopAppBarExpandedHeight + statusBarDp, modifier = Modifier .fillMaxWidth() .consumeWindowInsets(WindowInsets.statusBars), colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.Red, titleContentColor = Color.White ), scrollBehavior = scrollBehavior, ) } ) { scaffoldInnerPadding -> LazyColumn( modifier = Modifier .fillMaxSize() .padding(scaffoldInnerPadding) .background(Color.Gray), contentPadding = PaddingValues(16.dp) ) { items(50) { index -> Text( "Item $index", modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp), color = Color.Black ) } } }

Output:

Screen Recording

Note:

Please test this thoroughly, in my case there was some strange white flickering happening when scrolling fastly. This is the best that I managed to achieve.