sindrenm
08/09/2024, 12:12 AMNestedScrollConnection
.
To start with, in order to actually calculate the expanded height, I wrapped my carousel in a BoxWithConstraints
with the correct expanded size. That gives me access to maxWidth
inside of its scope. But that BoxWithConstraints
will then always be there with that size, which clearly isn't ideal. Ideally, the top app bar's height itself should be changing, not just the content inside of the BoxWithConstraints
.
I also tried a little bit with a Layout
, but I couldn't quite get that to work, either. Would love some help on this, if anyone has any ideas.
Code in 🧵.sindrenm
08/09/2024, 12:12 AM@Composable
fun CarouselTopAppBar(
details: ClubDetails,
nestedScrollConnection: CarouselTopAppBarNestedScrollConnection,
navigateUp: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(modifier) {
SatsTopAppBar(
title = details?.name.orEmpty(),
navigationIcon = { UpIconButton(navigateUp) },
)
BoxWithConstraints(
Modifier
.fillMaxWidth()
.aspectRatio(16f / 9f),
) {
LaunchedEffect(nestedScrollConnection, maxHeight) {
nestedScrollConnection.maxHeight = maxHeight
nestedScrollConnection.currentHeight = maxHeight
}
ClubImagesM3Carousel(
details.imageUrls,
Modifier.height(nestedScrollConnection.currentHeight),
)
}
}
}
sindrenm
08/09/2024, 12:12 AMclass CarouselTopAppBarNestedScrollConnection(
private val density: Density,
) : NestedScrollConnection {
internal var maxHeight: Dp = 1.dp // I don't like this, either
internal var currentHeight: Dp by mutableStateOf(maxHeight)
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
val delta = with(density) { available.y.toDp() }
if (delta > 0.dp) return Offset.Zero
return consumeScroll(delta)
}
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
val delta = with(density) { available.y.toDp() }
if (delta < 0.dp) return Offset.Zero
return consumeScroll(delta)
}
private fun consumeScroll(delta: Dp): Offset {
val previousHeight = currentHeight
val nextHeight = previousHeight + delta
currentHeight = nextHeight.coerceIn(0.dp, maxHeight)
val consumed = currentHeight - previousHeight
return with(density) { DpOffset(x = 0.dp, y = consumed).toOffset() }
}
}
sindrenm
08/09/2024, 12:19 AMBoxWithConstraints
that works exactly as it should, except that the height is hard-coded instead of being derived from the width.
@Composable
internal fun CarouselTopAppBar(
details: ClubDetails,
nestedScrollConnection: CarouselTopAppBarNestedScrollConnection,
navigateUp: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(modifier) {
SatsTopAppBar(
title = details?.name.orEmpty(),
navigationIcon = { UpIconButton(navigateUp) },
)
ClubImagesM3Carousel(
details.imageUrls,
Modifier.height(nestedScrollConnection.currentHeight),
)
}
}
class CarouselTopAppBarNestedScrollConnection(
private val density: Density,
) : NestedScrollConnection {
private val maxHeight = 252.dp
internal var currentHeight: Dp by mutableStateOf(maxHeight)
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
val delta = with(density) { available.y.toDp() }
if (delta > 0.dp) return Offset.Zero
return consumeScroll(delta)
}
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
val delta = with(density) { available.y.toDp() }
if (delta < 0.dp) return Offset.Zero
return consumeScroll(delta)
}
private fun consumeScroll(delta: Dp): Offset {
val previousHeight = currentHeight
val nextHeight = previousHeight + delta
currentHeight = nextHeight.coerceIn(0.dp, maxHeight)
val consumed = currentHeight - previousHeight
return with(density) { DpOffset(x = 0.dp, y = consumed).toOffset() }
}
}
Tunji Dahunsi
08/12/2024, 6:22 AMsindrenm
08/12/2024, 9:51 AMTunji Dahunsi
08/12/2024, 9:54 AM