Search code examples
androidkotlinandroid-jetpack-compose

Button Long Press Listener in Android jetpack compose


I am having an Android Composable UI with a Button.

How can I track button long press events? I got it working for the Text long press, but for Button, It is not working. Same way like below if I apply a modifier to the button, it is not working.

Text(
    text = view.text,
    fontSize = view.textFontSize.toInt().sp,
    fontWeight = FontWeight(view.textFontWeight.toInt()),
    color = Color(android.graphics.Color.parseColor(view.textColor)),
    modifier = Modifier.clickable(
        onClick = {
            println("Single Click")
        }, 
        onLongClick = {
            println("Long Click")
        }, 
        onDoubleClick = {
            println("Double Tap")
        },
    ),
)

Solution

  • The best way to handle this is to roll your own Button. The Material Button is basically just a Surface and a Row. The reason adding your own Modifier.clickable doesn't work is because one is already set.

    So, if you'd like to add onLongPress, etc you can copy/paste the default implementation and pass those lambdas in.

    @Composable
    @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
    fun Button(
        onClick: () -> Unit,
        modifier: Modifier = Modifier,
        onLongClick: (() -> Unit)? = null,
        onDoubleClick: (() -> Unit)? = null,
        enabled: Boolean = true,
        interactionState: InteractionState = remember { InteractionState() },
        elevation: ButtonElevation? = ButtonDefaults.elevation(),
        shape: Shape = MaterialTheme.shapes.small,
        border: BorderStroke? = null,
        colors: ButtonColors = ButtonDefaults.buttonColors(),
        contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
        content: @Composable RowScope.() -> Unit
    ) {
        val contentColor by colors.contentColor(enabled)
        Surface(
            shape = shape,
            color = colors.backgroundColor(enabled).value,
            contentColor = contentColor.copy(alpha = 1f),
            border = border,
            elevation = elevation?.elevation(enabled, interactionState)?.value ?: 0.dp,
            modifier = modifier.combinedClickable(
                onClick = onClick,
                onDoubleClick = onDoubleClick,
                onLongClick = onLongClick,
                enabled = enabled,
                role = Role.Button,
                interactionState = interactionState,
                indication = null
            )
        ) {
            Providers(LocalContentAlpha provides contentColor.alpha) {
                ProvideTextStyle(
                    value = MaterialTheme.typography.button
                ) {
                    Row(
                        Modifier
                            .defaultMinSizeConstraints(
                                minWidth = ButtonDefaults.MinWidth,
                                minHeight = ButtonDefaults.MinHeight
                            )
                            .indication(interactionState, rememberRipple())
                            .padding(contentPadding),
                        horizontalArrangement = Arrangement.Center,
                        verticalAlignment = Alignment.CenterVertically,
                        content = content
                    )
                }
            }
        }
    }
    

    Usage:

    Button(
        onClick = {},
        onLongClick = {},
        onDoubleClick = {}
    ) {
        Text(text = "I'm a button")
    }