Skip to content

Instantly share code, notes, and snippets.

@chiragthummar
Created June 25, 2023 07:25
Show Gist options
  • Save chiragthummar/7240ab3cbeb61bf7293e2e1cd6326049 to your computer and use it in GitHub Desktop.
Save chiragthummar/7240ab3cbeb61bf7293e2e1cd6326049 to your computer and use it in GitHub Desktop.
Increase user experience with bouncy click on any component of jetpack compose.
@OptIn(ExperimentalFoundationApi::class)
fun Modifier.bounceClickable(
dampingRatio: Float = 0.85f,
enabled: Boolean = true,
onClick: () -> Unit = {},
onDoubleClick: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null,
shape: Shape = RectangleShape,
useHapticFeedback: Boolean = true,
) = composed {
var buttonState by remember { mutableStateOf(ButtonState.Idle) }
val scale by animateFloatAsState(
targetValue = when (buttonState) {
ButtonState.Pressed -> dampingRatio
ButtonState.Idle -> 1f
}
)
val view = LocalView.current
this
.clip(shape)
.combinedClickable(
enabled = enabled,
onClick = onClick,
onDoubleClick = onDoubleClick,
onLongClick = onLongClick,
interactionSource = remember { MutableInteractionSource() },
indication = null,
)
.graphicsLayer {
this.shape = shape
this.scaleX = scale
this.scaleY = scale
}
.pointerInput(buttonState) {
awaitPointerEventScope {
buttonState = when (buttonState) {
ButtonState.Pressed -> {
waitForUpOrCancellation()
if (useHapticFeedback) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
ButtonState.Idle
}
ButtonState.Idle -> {
awaitFirstDown(false)
ButtonState.Pressed
}
}
}
}
}
@Composable
fun Example() {
Card(
modifier = Modifier
.bounceClickable(
dampingRatio = 0.95f,
onClick = {
},
shape = RoundedCornerShape(12.dp),
)
.fillMaxWidth(),
shape = RoundedCornerShape(12.dp),
) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment