Today’s tutorial will teach us how to implement onClick onLongPress on Button in KMP Kotlin Compose Multiplatform for Android and iOS platforms. This guide includes step-by-step processes, explanations of all the properties, and coding examples for handling click and long-click events.
Set onClick onLongPress on Button in KMP Compose Multiplatform
After extensive research in KMM(Kotlin Multiplatform Mobile), I found that the official button widget does not natively support the onLongPress event. It currently only supports the onClick event. So, to work around this and find a solution, I have integrated onClick and onLongPress into the Box widget. The Box widget supports all native events, including the ripple effect. It works like a button because I designed it at the button place.
Code for custom button using Box:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
@OptIn(ExperimentalFoundationApi::class) @Composable fun BoxWithClickAndLongPress( buttonText: String, onButtonClick: () -> Unit = {}, onLongPress: () -> Unit = {}, ) { val interactionSource = remember { MutableInteractionSource() } val indication = LocalIndication.current Box( modifier = Modifier .fillMaxSize() .background(Color(0xFF00B8D4), shape = RoundedCornerShape(8.dp)) .indication(interactionSource, indication) // Ripple effect .combinedClickable( interactionSource = interactionSource, indication = null, // Avoid duplicating the ripple effect onClick = { onButtonClick() }, onLongClick = { onLongPress() } ).padding(16.dp), contentAlignment = Alignment.Center ) { Text( text = buttonText, color = Color.White, fontSize = 21.sp, modifier = Modifier.padding(4.dp) ) } } |
Calling method:
1 2 3 4 5 |
BoxWithClickAndLongPress( buttonText = "Click or Long Press Me", onButtonClick = { println("Button clicked!") }, onLongPress = { println("Button long clicked!") } ) |
Code explanation:
I have written the code in Custom widget format. You must copy and paste the code, and you can reuse the button multiple times.
- fillMaxSize(): This function will set the Box button width to fill parent.
- background: To set the background color of the Box button widget.
- shape: Pass your desired shape; I am passing a rounded corner shape with a corner radius.
- indication: Enable ripple effect on Box widget.
- combinedClickable: Enable both onClick onLongPress on Box widget.
- contentAlignment: Setting Box inside child Text alignment vertically and horizontally center.
Complete source code for App.kt file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package com.app.test import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.indication import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @Composable fun App() { MaterialTheme { Box(modifier = Modifier.fillMaxSize()) { Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) .padding(24.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { BoxWithClickAndLongPress( buttonText = "Click or Long Press Me", onButtonClick = { println("Button clicked!") }, onLongPress = { println("Button long clicked!") } ) } } } } @OptIn(ExperimentalFoundationApi::class) @Composable fun BoxWithClickAndLongPress( buttonText: String, onButtonClick: () -> Unit = {}, onLongPress: () -> Unit = {}, ) { val interactionSource = remember { MutableInteractionSource() } val indication = LocalIndication.current Box( modifier = Modifier .fillMaxSize() .background(Color(0xFF00B8D4), shape = RoundedCornerShape(8.dp)) .indication(interactionSource, indication) // Ripple effect .combinedClickable( interactionSource = interactionSource, indication = null, // Avoid duplicating the ripple effect onClick = { onButtonClick() }, onLongClick = { onLongPress() } ).padding(16.dp), contentAlignment = Alignment.Center ) { Text( text = buttonText, color = Color.White, fontSize = 21.sp, modifier = Modifier.padding(4.dp) ) } } |
Screenshot of Android device:
Screenshot in iOS device:
Output: