Skip to content

Instantly share code, notes, and snippets.

@grumpyshoe
Created July 6, 2023 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grumpyshoe/c6117a485c55dd6363d8f16f30446992 to your computer and use it in GitHub Desktop.
Save grumpyshoe/c6117a485c55dd6363d8f16f30446992 to your computer and use it in GitHub Desktop.
Compose: Tinder like card dragging
fun Modifier.swiper(
enabled: Boolean,
state: Swipe,
onDragReset: () -> Unit = {},
onTap: () -> Unit,
onLongPress: () -> Unit,
onDrag: (SwipeDirection?, Float) -> Unit = { _, _ -> },
onDragRight: () -> Unit,
onDragLeft: () -> Unit,
): Modifier = composed {
val scope = rememberCoroutineScope()
var dragging by remember { mutableStateOf(false) }
val m = Modifier
.pointerInput(Unit) {
detectTapGestures(
onTap = {
onTap()
},
onLongPress = {
onLongPress()
},
)
}
.pointerInput(Unit) {
if (enabled) {
detectDragGestures(
onDragEnd = {
dragging = false
when {
abs(state.offsetX.targetValue) < state.maxWidth / 5 -> {
state
.reset(scope)
.invokeOnCompletion { onDragReset() }
}
state.offsetX.targetValue > 0 -> {
state
.accepted(scope)
.invokeOnCompletion { onDragRight() }
}
state.offsetX.targetValue < 0 -> {
state
.rejected(scope)
.invokeOnCompletion { onDragLeft() }
}
}
},
onDrag = { change, dragAmount ->
dragging = true
val original = Offset(state.offsetX.targetValue, state.offsetY.targetValue)
val summed = original + dragAmount
val newValue = Offset(
x = summed.x.coerceIn(-state.maxWidth, state.maxWidth),
y = state.offsetY.targetValue,
)
if (change.positionChange() != Offset.Zero) change.consume()
val direction = when {
summed.x > 0 && abs(summed.x) > state.maxWidth / 5 -> SwipeDirection.RIGHT
summed.x < 0 && abs(summed.x) > state.maxWidth / 5 -> SwipeDirection.LEFT
else -> null
}
onDrag(direction, summed.x)
state.drag(
scope,
newValue.x,
newValue.y,
)
},
)
}
}
/**
* Doing translation on the graphics layer
* which mimics the rotation and translation of tinder swipeable card. This can be improved
* if I start swiping a card it first rotates along edges left or right according to drag
*/
.graphicsLayer(
translationX = state.offsetX.value,
translationY = state.offsetY.value,
rotationZ = (state.offsetX.value / 60).coerceIn(-40f, 40f),
)
m
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment