androidwear-os

How to handle a long click event on wear compose?


I use the Wear Compose Version 1.2.1, which can handle onLongClick event with Modifier.combinedClickable(), but after the Wear Compose Version 1.3.x does not handle the long click event.

I think the feature has changed, but I don't know how to modify my code. Can anyone please suggest how can I convert the below-mentioned code for the Wear Compose Version 1.2.1,

Button(
    modifier = Modifier
        .height(48.dp)
        .width(48.dp)
        .padding(2.dp)
        .background(color = Color.Black)
        .combinedClickable(
            interactionSource = remember {
                MutableInteractionSource()
            },
            indication = null,
            enabled = true,
            onClick = {
                Toast.makeText(
                    context,
                    context.getString(R.string.long_press_to_stop),
                    Toast.LENGTH_SHORT
                ).show()
            },
            onLongClick = {
                Log.v("STOP", "onLongClick")
                // --- stop action ---
            },
        ),
    onClick = { },
    colors = ButtonDefaults.primaryButtonColors(backgroundColor =  Color.Black),
    enabled = true
) {
    Icon(
        painter = painterResource(id = R.drawable.baseline_stop_24),
        contentDescription = "Stop",
        tint = Color.LightGray
    )
}

The dependency section of my build.gradle.kts, just change the version number, then change the behaviour.

//val wearComposeVersion = "1.2.1"           // works OK
val wearComposeVersion = "1.3.0"             // does not handle long click event
implementation("androidx.wear.compose:compose-material:$wearComposeVersion")
implementation("androidx.wear.compose:compose-foundation:$wearComposeVersion")
implementation("androidx.wear.compose:compose-navigation:$wearComposeVersion")

Solution

  • Solution

    In a nutshell:

    1. Add a Box as the root content of the Button.
    2. Add the combinedClickable modifier to the Box, with the onLongClick.
    3. clearAndSetSemantics from Button in order to add onLongClick for accessibility.
        val interactionSource = remember { MutableInteractionSource() }
        val enabled = true
        val onClick = { /* your code */ }
        val onLongClick = { /* your code */ }
        Button(
            onClick = onClick,
            modifier = Modifier
                .size(DefaultButtonSize)
                .clearAndSetSemantics {
                    role = Role.Button
                    this.contentDescription = contentDescription
                    if (!enabled) {
                        disabled()
                    }
                    this.onClick(action = {
                        onClick()
                        true
                    })
                    if (onLongClick != null) {
                        this.onLongClick(action = {
                            onLongClick()
                            true
                        })
                    }
                },
            enabled = enabled,
            interactionSource = interactionSource,
        ) {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .clip(CircleShape)
                    .combinedClickable(
                        interactionSource = interactionSource,
                        indication = null, // From material Button
                        enabled = enabled,
                        onClick = onClick,
                        onLongClick = onLongClick,
                        role = Role.Button,
                    ),
            ) {
                // your content here
            }
        }
    

    You can see how it was done in Button.

    Alternative solution

    Use Button component from Horologist Compose Material library.

    Dependency:

    implementation "com.google.android.horologist:horologist-compose-material:<version>"
    

    Import:

    import com.google.android.horologist.compose.material.Button
    

    Usage:

    Button(
        id = R.drawable.baseline_stop_24,
        contentDescription = "Stop",
        onClick = { /* your code */ },
        onLongClick = { /* your code */ },
    )
    

    Context

    Wear Compose Version 1.3.x does not handle the long click event.

    Yes, as per findings of a member of the Wear Compose team:

    it's not possible to add now another clickable outside of the component ( eg extend Chip or Button externally and add other callbacks like LongClick) - for that we have to rewrite the component itself ( by using combinedClickable or other modifiers) .

    Be mindful that the solution above is tailored for Button component. There are more steps for other components with inner paddings like Chip and Card as per this comment.