Tweak BottomSheet code

This commit is contained in:
vfsfitvnm
2022-07-08 10:02:13 +02:00
parent fd4a1611e2
commit 87b2ff3788

View File

@@ -3,12 +3,9 @@ package it.vfsfitvnm.vimusic.ui.components
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.DraggableState import androidx.compose.foundation.gestures.DraggableState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.gestures.draggable import androidx.compose.foundation.gestures.detectVerticalDragGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
@@ -23,41 +20,18 @@ import androidx.compose.ui.graphics.Shape
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.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.input.pointer.util.addPointerInputChange
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.ranges.coerceAtMost
@Composable
@NonRestartableComposable
fun BottomSheet(
lowerBound: Dp,
upperBound: Dp,
modifier: Modifier = Modifier,
peekHeight: Dp = 0.dp,
elevation: Dp = 8.dp,
shape: Shape = RectangleShape,
handleOutsideInteractionsWhenExpanded: Boolean = false,
interactionSource: MutableInteractionSource? = null,
collapsedContent: @Composable BoxScope.() -> Unit,
content: @Composable BoxScope.() -> Unit
) {
BottomSheet(
state = rememberBottomSheetState(lowerBound, upperBound),
modifier = modifier,
peekHeight = peekHeight,
elevation = elevation,
shape = shape,
handleOutsideInteractionsWhenExpanded = handleOutsideInteractionsWhenExpanded,
interactionSource = interactionSource,
collapsedContent = collapsedContent,
content = content
)
}
@Composable @Composable
fun BottomSheet( fun BottomSheet(
state: BottomSheetState, state: BottomSheetState,
@@ -66,45 +40,19 @@ fun BottomSheet(
elevation: Dp = 8.dp, elevation: Dp = 8.dp,
shape: Shape = RectangleShape, shape: Shape = RectangleShape,
handleOutsideInteractionsWhenExpanded: Boolean = false, handleOutsideInteractionsWhenExpanded: Boolean = false,
interactionSource: MutableInteractionSource? = null,
collapsedContent: @Composable BoxScope.() -> Unit, collapsedContent: @Composable BoxScope.() -> Unit,
content: @Composable BoxScope.() -> Unit content: @Composable BoxScope.() -> Unit
) { ) {
var lastOffset by remember {
mutableStateOf(state.value)
}
Box { Box {
if (handleOutsideInteractionsWhenExpanded && !state.isCollapsed) { if (handleOutsideInteractionsWhenExpanded && !state.isCollapsed) {
Spacer( Spacer(
modifier = Modifier modifier = Modifier
.pointerInput(Unit) { .pointerInput(state) {
detectTapGestures { detectTapGestures {
state.collapse() state.collapse()
} }
} }
.draggable( .draggableBottomSheet(state)
state = state,
onDragStarted = {
lastOffset = state.value
},
onDragStopped = { velocity ->
if (velocity.absoluteValue > 300 && lastOffset != state.value) {
if (lastOffset > state.value) {
state.collapse()
} else {
state.expand()
}
} else {
if (state.upperBound - state.value > state.value - state.lowerBound) {
state.collapse()
} else {
state.expand()
}
}
},
orientation = Orientation.Vertical
)
.drawBehind { .drawBehind {
drawRect(color = Color.Black.copy(alpha = 0.5f * state.progress)) drawRect(color = Color.Black.copy(alpha = 0.5f * state.progress))
} }
@@ -122,36 +70,14 @@ fun BottomSheet(
} }
.shadow(elevation = elevation, shape = shape) .shadow(elevation = elevation, shape = shape)
.clip(shape) .clip(shape)
.draggable( .draggableBottomSheet(state)
state = state, .pointerInput(state) {
interactionSource = interactionSource, if (!state.isRunning && state.isCollapsed) {
onDragStarted = { detectTapGestures {
lastOffset = state.value state.expand()
},
onDragStopped = { velocity ->
if (velocity.absoluteValue > 300 && lastOffset != state.value) {
if (lastOffset > state.value) {
state.collapse()
} else {
state.expand()
}
} else {
if (state.upperBound - state.value > state.value - state.lowerBound) {
state.collapse()
} else {
state.expand()
}
} }
}, }
orientation = Orientation.Vertical }
)
.clickable(
enabled = !state.isRunning && state.isCollapsed,
indication = null,
interactionSource = interactionSource
?: remember { MutableInteractionSource() },
onClick = state.expand
)
.fillMaxSize() .fillMaxSize()
) { ) {
if (!state.isCollapsed) { if (!state.isCollapsed) {
@@ -299,3 +225,36 @@ fun rememberBottomSheetState(lowerBound: Dp, upperBound: Dp): BottomSheetState {
) )
} }
} }
private fun Modifier.draggableBottomSheet(state: BottomSheetState) = pointerInput(state) {
var initialValue = 0.dp
val velocityTracker = VelocityTracker()
detectVerticalDragGestures(
onDragStart = {
initialValue = state.value
},
onVerticalDrag = { change, dragAmount ->
velocityTracker.addPointerInputChange(change)
state.dispatchRawDelta(dragAmount)
},
onDragEnd = {
val velocity = velocityTracker.calculateVelocity().y.absoluteValue
velocityTracker.resetTracking()
if (velocity.absoluteValue > 300 && initialValue != state.value) {
if (initialValue > state.value) {
state.collapse()
} else {
state.expand()
}
} else {
if (state.upperBound - state.value > state.value - state.lowerBound) {
state.collapse()
} else {
state.expand()
}
}
}
)
}