Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement long-press FAB in jetpack compose?

enter image description here

Is it possible to implement a long-press for the fab that shows small buttons with labels on top of the fab without additional components?

If not how to implement it with additional components but the same visual result?

My current FAB looks like this: https://codeberg.org/pabloscloud/Overload/src/commit/eae4132fd66d58d9ee52fe51ed18eb5bc2cd9f53/app/src/main/java/cloud/pablos/overload/ui/tabs/home/HomeTabFab.kt

FloatingActionButton(
        onClick = {
            /* onClick - event */
        },
        modifier = Modifier
            .padding(10.dp),
        containerColor = MaterialTheme.colorScheme.secondaryContainer,
        contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.padding(8.dp),
        ) {
            Icon(
                imageVector = Icons.Default.PlayArrow
                contentDescription = stringResource(id = R.string.edit),
                modifier = Modifier.padding(8.dp, 0.dp, 0.dp, 0.dp),

            )
            TextView(
                text = stringResource(id = R.string.start),
                modifier = Modifier.padding(8.dp, 0.dp, 8.dp, 0.dp),
            )
        }
    }

I tried using other components instead of a FAB but couldn't get it to act and look the same.

like image 702
Pablo Avatar asked Sep 07 '25 17:09

Pablo


1 Answers

You can build this in 3 ways as i can think of probably there are other ways too.

You can use InteractionSource to determine how long fab is pressed with collectLatest because need to trigger click on fast clicks and cancel previous action.

Second option is to copy-paste source code and use it with Surface that doesn't have onClick param and add Modifer.combinedClickable.

Third option is to create a Modifier.pointerInput(){} with PointerEventPass.Initial to get long click event before FloatingActionButton or Button.

I will post first option because this one is easier than copy-paste and modify solution.

You can also apply this solution to Button since it also takes InteractionSource as param.

enter image description here

@Preview
@Composable
private fun Test() {
    
    val context = LocalContext.current

    val interactionSource = remember { MutableInteractionSource() }

    val viewConfiguration = LocalViewConfiguration.current


    LaunchedEffect(interactionSource) {
        var isLongClick = false

        interactionSource.interactions.collectLatest { interaction ->
            when (interaction) {
                is PressInteraction.Press -> {
                    isLongClick = false
                    delay(viewConfiguration.longPressTimeoutMillis)
                    isLongClick = true
                    Toast.makeText(context, "Long click", Toast.LENGTH_SHORT).show()
                }
                is PressInteraction.Release -> {
                    if (isLongClick.not()){
                        Toast.makeText(context, "click", Toast.LENGTH_SHORT).show()
                    }

                }
                is PressInteraction.Cancel -> {
                    isLongClick = false
                }
            }
        }
    }

    
    FloatingActionButton(
        interactionSource = interactionSource,
        onClick = {},
        modifier = Modifier
            .padding(10.dp),
        containerColor = MaterialTheme.colorScheme.secondaryContainer,
        contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.padding(8.dp),
        ) {
            Icon(
                imageVector = Icons.Default.PlayArrow,
                        contentDescription = null,
                modifier = Modifier.padding(8.dp, 0.dp, 0.dp, 0.dp),

                )
            Text(
                text = "Start",
                modifier = Modifier.padding(8.dp, 0.dp, 8.dp, 0.dp),
            )
        }
    }
}
like image 192
Thracian Avatar answered Sep 10 '25 10:09

Thracian