There are so many ways to add click in Compose, this article makes a brief summary
1. Modifier.clickable
This is the most common and easiest way, as shown below
Box(
modifier = Modifier.clickable {
// 处理点击事件
}
)
When a click occurs, in addition to corresponding event processing, it will also trigger theme effects such as water ripples (Ripple).
It should be noted that for the Composable of the Button class, it is not recommended to use Modifier.clickable, and its own onClick parameter should be used, although there are some additional processing inside it besides calling Modifier.clickable
Button (
onClick = {
// 处理点击事件
}) {
//...
}
2. Modifier.combinedClickable
In addition to the click event, it can handle double-click, long-press and other click events at the same time
Box(
modifier = Modifier
.combinedClickable(
onClick = {
// 单击
},
onDoubleClick = {
// 双击
},
onLongClick = {
// 长按
}
)
)
Like Modifier.clickable, clicking will trigger the water ripple effect.
3. Modifier.pointerInput
pointerInput is the entry point for processing all gesture events in Compose, similar to onTouch of traditional views. The click gesture can be recognized here, and the corresponding priority is higher than clickable, but it will not trigger effects such as water ripples
Box(
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = {
},
onLongPress = {
},
onPress = {
},
onTap = {
}
)
},
)
As above, detectTapGestures
you can handle various click events. Similarly, drag events detectDragGestures
can be handled.
In addition to the corresponding events in detectTapGestures, you can also offset
get , as follows:
detectTapGestures(
onTap = {
val x = it.x
val y = it.y
},
)
In addition, when onPress
the event , you can also get the callback when the finger leaves
var pressing by remember {
mutableStateOf(false) }
Box(
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onPress = {
// 按下
pressing = true
val isCanceled = tryAwaitRelease()
// 离开
pressing = false
},
)
},
)
During OnPress, calling tryAwaitRelease
will suspend the current function, and continue execution when the finger leaves.
tryAwaitRelease returns a bool value: true means the finger is lifted within the current area, false means the finger has moved out of the current area. Similar to UP and CANCEL events for traditional views.
It can be seen that pointerInput can manage events more finely.
4. ViewConfiguration
If you want to further refine the control of events, such as setting the minimum click interval , long press timeout , etc., you can use ViewConfiguration to configure. Currently, the items that can be set are as follows:
It can be seen that the configuration of ViewConfiguration mainly affects combinedClickable and pointerInput.
LocalViewConfiguration
The global default ViewConfiguration can be obtained by . We can implement custom ViewConfiguration based on the default configuration by inheritance and rewriting. Then also realize the custom configuration of its internal local UI with the help of CompositionLocal.
The following example shows how to customize the long press timeout:
// 自定义 ViewConfiguration
class CustomViewConfiguration(
private val defaultViewConfiguration: ViewConfiguration //传入默认配置
) : ViewConfiguration by defaultViewConfiguration {
// 自定义长按超时3000ms
override val longPressTimeoutMillis: Long = 3000
}
@Composable
fun Sample() {
// 获取全局默认 ViewConfiguration
val defaultViewConfiguration = LocalViewConfiguration.current
// 基于默认配置创建自定义 CustomViewConfiguration
val viewConfiguration = remember {
CustomViewConfiguration(defaultViewConfiguration)
}
CompositionLocalProvider(
LocalViewConfiguration provides viewConfiguration
) {
// 内部的事件配置都受到 CustomViewConfiguration 影响
Box(
modifier = Modifier
.combinedClickable(
onLongClick = {
// ...
},
)
)
}
}
It is worth mentioning that it is ViewConfiguration.minimumTouchTargetSize
used to set the minimum size of the gesture responsive area. This is very practical and can solve the problem that some small-sized controls on the interface are more difficult to touch. So, by setting, it is possible that the area of the Composable pointerInput
that can respond to events is larger than the area it actually renders. The offset value obtained at this time may be a negative number, or it may exceed the size of Compose.
The default value of minimumTouchTargetSize is 48.dp, so it is not surprising if we get a negative offset value during development.
class CustomViewConfiguration(
private val defaultViewConfiguration: ViewConfiguration
) : ViewConfiguration by defaultViewConfiguration {
override val minimumTouchTargetSize: DpSize = DpSize(0.dp, 0.dp)
}
As an experiment, if you set it to 0.dp, you will never get a negative offset. Of course, we do not recommend doing this, as it will cause difficult touches.