长按事件 · 组合点击

Modifier.combinedClickable

✏️ 在 Jetpack Compose 中,combinedClickable 让长按与普通点击优雅共存。本课详解 onLongClick 手势识别、防冲突机制及最佳实践。

📌 参数对比
参数类型说明触发时机
onClick() -> Unit普通点击回调手指抬起后(无长按)
onLongClick() -> Unit长按回调按住超过 ~500ms 且未移动
onDoubleClick() -> Unit双击回调(可选)两次快速点击
💻 标准用法 · 点击 + 长按
@Composable
fun LongClickExample() {
    var status by remember { mutableStateOf("等待手势...") }

    Box(
        modifier = Modifier
            .size(220.dp, 120.dp)
            .background(Color(0xFFF7E8C8), shape = RoundedCornerShape(28.dp))
            .combinedClickable(
                onClick = { status = "👆 普通点击" },
                onLongClick = { status = "⏱️ 长按触发 (500ms)" },
                onDoubleClick = { status = "👆👆 双击" }   // 可选
            ),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = status,
            fontSize = 18.sp,
            fontWeight = FontWeight.SemiBold,
            color = Color(0xFF2D5A27)
        )
    }
}

✅ 共存机制:系统通过手势超时区分点击与长按。长按触发后 onClick 不会调用,避免冲突。

🧠 手势决策流程
手指按下 计时器 > 500ms onLongClick 手指抬起 (≤500ms) onClick 按下瞬间 长按成功 短按抬起
✨ 共存原则 & 注意事项
  • combinedClickable 自动处理手势冲突,无需额外检测。
  • 长按触发后 onClick 会被屏蔽,不会同时响应。
  • 如需自定义长按时长,可使用 LongPressGesture + detectTapGestures 更底层 API。
  • 避免在 onLongClick 中执行长时间操作,考虑使用协程。
  • 可配合 Modifier.pointerInput 实现更复杂的长按拖拽。
⚙️ 底层手势 · 自定义长按
@Composable
fun CustomLongClick() {
    var event by remember { mutableStateOf("") }
    Box(
        modifier = Modifier
            .size(200.dp, 100.dp)
            .background(Color(0xFFF0E3C8), RoundedCornerShape(24.dp))
            .pointerInput(Unit) {
                detectTapGestures(
                    onLongPress = { offset ->
                        event = "长按 @ ${offset.x.toInt()}, ${offset.y.toInt()}"
                    },
                    onTap = { event = "单击" },
                    onDoubleTap = { event = "双击" }
                )
            },
        contentAlignment = Alignment.Center
    ) {
        Text(text = event, fontSize = 16.sp, color = Color(0xFF2D5A27))
    }
}

💡 detectTapGestures 默认长按阈值约 500ms,可通过 longPressTimeout 参数调整。

📱 典型场景
场景推荐方案说明
列表项操作combinedClickable点击进入详情,长按弹出菜单
图片预览combinedClickable单击查看,长按保存/分享
游戏按钮pointerInput + detectTapGestures需要自定义长按时间或位置
文本选择combinedClickable + 拖拽长按进入选择模式