Fix BottomSheet behaviour on configuration change (regression of #457e6712)

This commit is contained in:
vfsfitvnm 2022-07-25 13:12:52 +02:00
parent 457e6712d4
commit 1d259ebaa6
3 changed files with 45 additions and 37 deletions

View file

@ -216,9 +216,9 @@ class MainActivity : ComponentActivity() {
when (val uri = uri) { when (val uri = uri) {
null -> { null -> {
val playerBottomSheetState = rememberBottomSheetState( val playerBottomSheetState = rememberBottomSheetState(
lowerBound = 0.dp, dismissedBound = 0.dp,
collapsedBound = Dimensions.collapsedPlayer, collapsedBound = Dimensions.collapsedPlayer,
upperBound = maxHeight, expandedBound = maxHeight,
isExpanded = expandPlayerBottomSheet isExpanded = expandPlayerBottomSheet
) )

View file

@ -52,14 +52,14 @@ fun BottomSheet(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
peekHeight: Dp = 0.dp, peekHeight: Dp = 0.dp,
elevation: Dp = 8.dp, elevation: Dp = 8.dp,
onSwiped: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null,
collapsedContent: @Composable BoxScope.() -> Unit, collapsedContent: @Composable BoxScope.() -> Unit,
content: @Composable BoxScope.() -> Unit content: @Composable BoxScope.() -> Unit
) { ) {
Box( Box(
modifier = modifier modifier = modifier
.offset { .offset {
val y = (state.upperBound - state.value + peekHeight) val y = (state.expandedBound - state.value + peekHeight)
.roundToPx() .roundToPx()
.coerceAtLeast(0) .coerceAtLeast(0)
IntOffset(x = 0, y = y) IntOffset(x = 0, y = y)
@ -87,25 +87,25 @@ fun BottomSheet(
if (velocity.absoluteValue > 300 && initialValue != state.value) { if (velocity.absoluteValue > 300 && initialValue != state.value) {
when (initialValue) { when (initialValue) {
state.upperBound -> state.collapse() state.expandedBound -> state.collapse()
state.collapsedBound -> if (initialValue > state.value && onSwiped != null) { state.collapsedBound -> if (initialValue > state.value && onDismiss != null) {
state.swipe() state.dismiss()
onSwiped.invoke() onDismiss.invoke()
} else { } else {
state.expand() state.expand()
} }
} }
} else { } else {
val l0 = state.lowerBound val l0 = state.dismissedBound
val l1 = (state.collapsedBound - state.lowerBound) / 2 val l1 = (state.collapsedBound - state.dismissedBound) / 2
val l2 = (state.upperBound - state.collapsedBound) / 2 val l2 = (state.expandedBound - state.collapsedBound) / 2
val l3 = state.upperBound val l3 = state.expandedBound
when (state.value) { when (state.value) {
in l0..l1 -> { in l0..l1 -> {
if (onSwiped != null) { if (onDismiss != null) {
state.swipe() state.dismiss()
onSwiped.invoke() onDismiss.invoke()
} else { } else {
state.collapse() state.collapse()
} }
@ -126,7 +126,7 @@ fun BottomSheet(
content() content()
} }
if (!state.isExpanded && (onSwiped == null || !state.isDismissed)) { if (!state.isExpanded && (onDismiss == null || !state.isDismissed)) {
Box( Box(
modifier = Modifier modifier = Modifier
.graphicsLayer { .graphicsLayer {
@ -150,13 +150,13 @@ class BottomSheetState(
draggableState: DraggableState, draggableState: DraggableState,
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
private val animatable: Animatable<Dp, AnimationVector1D>, private val animatable: Animatable<Dp, AnimationVector1D>,
private val onWasExpandedChanged: (Boolean) -> Unit, private val onAnchorChanged: (Int) -> Unit,
val collapsedBound: Dp, val collapsedBound: Dp,
) : DraggableState by draggableState { ) : DraggableState by draggableState {
val lowerBound: Dp val dismissedBound: Dp
get() = animatable.lowerBound!! get() = animatable.lowerBound!!
val upperBound: Dp val expandedBound: Dp
get() = animatable.upperBound!! get() = animatable.upperBound!!
val value by animatable.asState() val value by animatable.asState()
@ -178,14 +178,14 @@ class BottomSheetState(
} }
private fun collapse(animationSpec: AnimationSpec<Dp>) { private fun collapse(animationSpec: AnimationSpec<Dp>) {
onWasExpandedChanged(false) onAnchorChanged(collapsedAnchor)
coroutineScope.launch { coroutineScope.launch {
animatable.animateTo(collapsedBound, animationSpec) animatable.animateTo(collapsedBound, animationSpec)
} }
} }
fun expand(animationSpec: AnimationSpec<Dp>) { fun expand(animationSpec: AnimationSpec<Dp>) {
onWasExpandedChanged(true) onAnchorChanged(expandedAnchor)
coroutineScope.launch { coroutineScope.launch {
animatable.animateTo(animatable.upperBound!!, animationSpec) animatable.animateTo(animatable.upperBound!!, animationSpec)
} }
@ -207,8 +207,8 @@ class BottomSheetState(
expand(tween(300)) expand(tween(300))
} }
fun swipe() { fun dismiss() {
onWasExpandedChanged(false) onAnchorChanged(dismissedAnchor)
coroutineScope.launch { coroutineScope.launch {
animatable.animateTo(animatable.lowerBound!!) animatable.animateTo(animatable.lowerBound!!)
} }
@ -277,24 +277,34 @@ class BottomSheetState(
} }
} }
private const val expandedAnchor = 2
private const val collapsedAnchor = 1
private const val dismissedAnchor = 0
@Composable @Composable
fun rememberBottomSheetState( fun rememberBottomSheetState(
lowerBound: Dp, dismissedBound: Dp,
upperBound: Dp, expandedBound: Dp,
collapsedBound: Dp = lowerBound, collapsedBound: Dp = dismissedBound,
isExpanded: Boolean = false isExpanded: Boolean = false
): BottomSheetState { ): BottomSheetState {
val density = LocalDensity.current val density = LocalDensity.current
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
var wasExpanded by rememberSaveable { var previousAnchor by rememberSaveable {
mutableStateOf(isExpanded) mutableStateOf(if (isExpanded) expandedAnchor else collapsedAnchor)
} }
return remember(lowerBound, upperBound, collapsedBound, coroutineScope) { return remember(dismissedBound, expandedBound, collapsedBound, coroutineScope) {
val animatable = val initialValue = when (previousAnchor) {
Animatable(if (wasExpanded) upperBound else lowerBound, Dp.VectorConverter).also { expandedAnchor -> expandedBound
it.updateBounds(lowerBound.coerceAtMost(upperBound), upperBound) collapsedAnchor -> collapsedBound
dismissedAnchor -> dismissedBound
else -> error("Unknown BottomSheet anchor")
}
val animatable = Animatable(initialValue, Dp.VectorConverter).also {
it.updateBounds(dismissedBound.coerceAtMost(expandedBound), expandedBound)
} }
BottomSheetState( BottomSheetState(
@ -303,9 +313,7 @@ fun rememberBottomSheetState(
animatable.snapTo(animatable.value - with(density) { delta.toDp() }) animatable.snapTo(animatable.value - with(density) { delta.toDp() })
} }
}, },
onWasExpandedChanged = { onAnchorChanged = { previousAnchor = it },
wasExpanded = it
},
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
animatable = animatable, animatable = animatable,
collapsedBound = collapsedBound collapsedBound = collapsedBound

View file

@ -147,7 +147,7 @@ fun PlayerView(
BottomSheet( BottomSheet(
state = layoutState, state = layoutState,
modifier = modifier, modifier = modifier,
onSwiped = binder.player::clearMediaItems, onDismiss = binder.player::clearMediaItems,
collapsedContent = { collapsedContent = {
Row( Row(
horizontalArrangement = Arrangement.spacedBy(12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp),
@ -315,7 +315,7 @@ fun PlayerView(
} }
PlayerBottomSheet( PlayerBottomSheet(
layoutState = rememberBottomSheetState(64.dp, layoutState.upperBound), layoutState = rememberBottomSheetState(64.dp, layoutState.expandedBound),
isShowingLyrics = isShowingLyrics, isShowingLyrics = isShowingLyrics,
onShowLyrics = { onShowLyrics = {
isShowingStatsForNerds = false isShowingStatsForNerds = false