Improve bottom sheets

This commit is contained in:
MM20 2023-03-13 18:33:22 +01:00
parent fc7fcd7553
commit 5f31ded8c3
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389

View File

@ -2,7 +2,10 @@ package de.mm20.launcher2.ui.component
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
@ -31,23 +34,29 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toDp
import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.ktx.toPixels
import kotlinx.coroutines.launch
import kotlin.math.roundToInt import kotlin.math.roundToInt
@Composable @Composable
@ -61,12 +70,15 @@ fun BottomSheetDialog(
dismissOnBackPress: () -> Boolean = { true }, dismissOnBackPress: () -> Boolean = { true },
content: @Composable (paddingValues: PaddingValues) -> Unit, content: @Composable (paddingValues: PaddingValues) -> Unit,
) { ) {
val scope = rememberCoroutineScope()
val swipeState = remember { val swipeState = remember {
SwipeableState( SwipeableState(
initialValue = SwipeState.Dismiss, initialValue = SwipeState.Dismiss,
confirmStateChange = { confirmStateChange = {
if (it == SwipeState.Dismiss) { if (it == SwipeState.Dismiss) {
if (swipeToDismiss()) onDismissRequest() if (swipeToDismiss()) {
onDismissRequest()
}
else return@SwipeableState false else return@SwipeableState false
} }
return@SwipeableState true return@SwipeableState true
@ -121,11 +133,10 @@ fun BottomSheetDialog(
} }
} }
Dialog( Popup(
properties = DialogProperties( properties = PopupProperties(
usePlatformDefaultWidth = false, dismissOnBackPress = dismissOnBackPress(),
dismissOnClickOutside = true, dismissOnClickOutside = swipeToDismiss(),
dismissOnBackPress = dismissOnBackPress()
), ),
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
) { ) {
@ -135,6 +146,25 @@ fun BottomSheetDialog(
contentAlignment = Alignment.BottomCenter contentAlignment = Alignment.BottomCenter
) { ) {
val maxHeightPx = maxHeight.toPixels() val maxHeightPx = maxHeight.toPixels()
val scrimAlpha by animateFloatAsState(
if (swipeState.targetValue == SwipeState.Dismiss) 0f else 0.32f,
label = "Scrim alpha"
)
Box(modifier = Modifier
.background(MaterialTheme.colorScheme.scrim.copy(alpha = scrimAlpha))
.fillMaxSize()
.pointerInput(onDismissRequest, swipeToDismiss) {
detectTapGestures {
if (swipeToDismiss()) {
scope.launch {
swipeState.animateTo(SwipeState.Dismiss)
onDismissRequest()
}
}
}
}
)
Column( Column(
modifier = Modifier modifier = Modifier
@ -164,6 +194,11 @@ fun BottomSheetDialog(
Surface( Surface(
modifier = Modifier modifier = Modifier
.nestedScroll(nestedScrollConnection) .nestedScroll(nestedScrollConnection)
.animateContentSize()
.onSizeChanged {
height = it.height.toFloat()
}
.offset { IntOffset(0, swipeState.offset.value.roundToInt()) }
.swipeable( .swipeable(
swipeState, swipeState,
anchors = anchors, anchors = anchors,
@ -177,11 +212,6 @@ fun BottomSheetDialog(
}, },
resistance = null resistance = null
) )
.animateContentSize()
.onSizeChanged {
height = it.height.toFloat()
}
.offset { IntOffset(0, swipeState.offset.value.roundToInt()) }
.fillMaxWidth() .fillMaxWidth()
.weight(1f, false), .weight(1f, false),
shape = MaterialTheme.shapes.extraLarge.copy( shape = MaterialTheme.shapes.extraLarge.copy(
@ -213,6 +243,7 @@ fun BottomSheetDialog(
if (confirmButton != null || dismissButton != null) { if (confirmButton != null || dismissButton != null) {
val elevation by animateDpAsState(if (swipeState.offset.value == 0f) 0.dp else 1.dp) val elevation by animateDpAsState(if (swipeState.offset.value == 0f) 0.dp else 1.dp)
val alpha by animateFloatAsState(if (swipeState.targetValue == SwipeState.Dismiss) 0f else 1f)
Surface( Surface(
modifier = Modifier modifier = Modifier
.wrapContentHeight() .wrapContentHeight()