@@ -34,6 +34,7 @@ import androidx.compose.foundation.layout.calculateStartPadding
3434import androidx.compose.foundation.layout.fillMaxSize
3535import androidx.compose.foundation.layout.only
3636import androidx.compose.foundation.lazy.LazyColumn
37+ import androidx.compose.foundation.lazy.grid.LazyGridState
3738import androidx.compose.foundation.lazy.grid.rememberLazyGridState
3839import androidx.compose.foundation.lazy.items
3940import androidx.compose.material.icons.Icons
@@ -42,6 +43,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
4243import androidx.compose.material3.MaterialTheme
4344import androidx.compose.material3.Scaffold
4445import androidx.compose.material3.TopAppBarDefaults
46+ import androidx.compose.material3.TopAppBarState
4547import androidx.compose.material3.rememberTopAppBarState
4648import androidx.compose.runtime.Composable
4749import androidx.compose.runtime.LaunchedEffect
@@ -53,6 +55,7 @@ import androidx.compose.runtime.remember
5355import androidx.compose.runtime.setValue
5456import androidx.compose.ui.Modifier
5557import androidx.compose.ui.graphics.Color
58+ import androidx.compose.ui.input.nestedscroll.nestedScroll
5659import androidx.compose.ui.platform.LocalDensity
5760import androidx.compose.ui.platform.LocalLayoutDirection
5861import androidx.compose.ui.unit.dp
@@ -260,8 +263,9 @@ fun AppList(eventHandler: AppListEventHandler, paddingValues: PaddingValues) {
260263 AppListScaffold (
261264 listState = rememberAppListState(viewModel),
262265 eventHandler = rememberCompOptionsEventHandler(viewModel),
266+ appBarState = appBarState,
267+ listScrollState = scrollState,
263268 paddingValues = paddingValues,
264- contentOffsetProgress = { - headerState.headerOffsetY },
265269 onAppBarOpacityChange = eventHandler::onAppBarOpacityChange,
266270 ) { contentPadding ->
267271 AppListGrid (
@@ -303,33 +307,43 @@ interface AppListState {
303307private fun AppListScaffold (
304308 listState : AppListState ,
305309 eventHandler : CompositeOptionsEventHandler ,
306- paddingValues : PaddingValues ,
307- contentOffsetProgress : () -> Int ,
310+ appBarState : TopAppBarState = rememberTopAppBarState(),
311+ listScrollState : LazyGridState = rememberLazyGridState(),
312+ paddingValues : PaddingValues = PaddingValues (),
308313 onAppBarOpacityChange : (Float ) -> Unit = {},
309314 content : @Composable (PaddingValues ) -> Unit
310315) {
311316 var showListOptions by remember { mutableIntStateOf(0 ) }
317+ val scrollBehavior = TopAppBarDefaults .pinnedScrollBehavior(appBarState)
312318 Scaffold (
319+ modifier = Modifier .nestedScroll(scrollBehavior.nestedScrollConnection),
313320 topBar = {
314321 val density = LocalDensity .current
315- val toolbarOpacity by remember(density) {
322+ val toolbarOpacity by remember(density, appBarState ) {
316323 val toolbarHeight = with (density) { 100 .dp.toPx() }
317324 val headerHeight = (toolbarHeight * 1.8f ).roundToInt()
318325 derivedStateOf {
319- ((contentOffsetProgress() - headerHeight) / toolbarHeight)
320- .coerceIn(0f , 0.96f ).mapIf({ it <= 0.06f }, { 0f })
326+ val fraction = if (listScrollState.firstVisibleItemIndex == 0 ) {
327+ // use first item offset when scrolled to top
328+ (listScrollState.firstVisibleItemScrollOffset - headerHeight) / toolbarHeight
329+ } else {
330+ (- appBarState.contentOffset - headerHeight) / toolbarHeight
331+ }
332+ fraction.coerceIn(0f , 0.96f ).mapIf({ it <= 0.06f }, { 0f })
321333 }
322334 }
323335 LaunchedEffect (toolbarOpacity) {
324336 onAppBarOpacityChange(toolbarOpacity)
325337 }
326338
339+ val containerColor = MaterialTheme .colorScheme.surface.copy(alpha = toolbarOpacity)
327340 AppListBar (
328341 isRefreshing = listState.isRefreshing,
329342 windowInsets = paddingValues.asInsets()
330343 .only(WindowInsetsSides .Horizontal + WindowInsetsSides .Top ),
331344 colors = TopAppBarDefaults .topAppBarColors(
332- containerColor = MaterialTheme .colorScheme.surface.copy(alpha = toolbarOpacity))
345+ containerColor = containerColor, scrolledContainerColor = containerColor),
346+ scrollBehavior = scrollBehavior,
333347 ) {
334348 AppListBarAction (
335349 icon = Icons .Outlined .CheckCircle ,
@@ -358,6 +372,7 @@ private fun AppListScaffold(
358372 )
359373}
360374
375+ @OptIn(ExperimentalMaterial3Api ::class )
361376@PreviewCombinedColorLayout
362377@Composable
363378private fun AppListPreview () {
@@ -373,8 +388,6 @@ private fun AppListPreview() {
373388 AppListScaffold (
374389 listState = listState,
375390 eventHandler = remember { PseudoCompOptionsEventHandler () },
376- paddingValues = PaddingValues (),
377- contentOffsetProgress = { 50 },
378391 content = { _ -> Box (Modifier .fillMaxSize().background(Color .DarkGray )) }
379392 )
380393 }
0 commit comments