👆 双击事件 · onDoubleTap

手势精讲 #4
📱 Compose · detectTapGestures 🎯 双击 & 单击 · 冲突消除

📌 双击事件本质

detectTapGestures 是 Compose 中处理轻触手势的利器。它内部通过时间窗口与距离判定区分单击、双击、长按等。双击事件 onDoubleTap 会在极短时间(通常 300ms)内检测到两次点击时触发。

⚡ 核心时序: 第一次点击后,系统不会立刻触发单击,而是等待一个超时窗口,若在此窗口内收到第二次点击,则判定为双击并取消单击。

📋 手势检测对比表

手势类型回调触发条件典型延迟
单击 (Tap)onTap单次按压并抬起,无二次点击约 300ms (等待双击超时)
双击 (DoubleTap)onDoubleTap两次快速点击 (间隔 < 300ms)第二次按下时立即触发
长按 (LongPress)onLongPress按压持续 > 500ms500ms 后触发

⚡ 双击 vs 单击 · 冲突根源

当同时监听 onTap 和 onDoubleTap 时,每次单击都会延迟触发,因为系统需要等待“是否会有第二次点击”。这导致单击响应变慢,且双击时也会错误触发单击。这就是经典的 单击/双击冲突。

🧩 冲突场景图解

单击 onTap 触发 双击 onDoubleTap 触发 ⚠️ 若同时监听 onTap,第一次点击会延迟 等待超时 (约300ms)

👆 单击需要等待双击超时窗口,造成延迟;双击时若处理不当会先触发单击。

🧹 冲突解决方案

💡 combinedClickable —— 官方推荐

Compose 1.2+ 提供了 Modifier.combinedClickable,内部已处理好双击与单击的冲突,无需手动管理时序。

// 使用 combinedClickable 优雅解决冲突
Modifier.combinedClickable(
    onClick = { 
        // 单击回调 (有轻微延迟,但不会误触)
        println("单击")
    },
    onDoubleClick = { 
        // 双击回调 (快速响应)
        println("双击 👍")
    },
    onLongClick = { 
        println("长按")
    }
)

🛠️ detectTapGestures 实战

下面展示使用 detectTapGestures 同时监听单击与双击,并加入 防抖/冲突标记 的典型模式。

@Composable
fun DoubleTapSample() {
    var doubleTapFlag by remember { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .size(200.dp)
            .background(Color(0xFFF5E8D8), shape = RoundedCornerShape(28.dp))
            .pointerInput(Unit) {
                detectTapGestures(
                    onTap = {
                        // 延迟执行,等待双击判定
                        if (!doubleTapFlag) {
                            // 单击逻辑 (300ms后执行)
                            println("单击事件")
                        }
                        doubleTapFlag = false
                    },
                    onDoubleTap = {
                        doubleTapFlag = true
                        println("双击事件 🎯")
                    }
                )
            }
    ) {
        // 内容
    }
}
📌 注意: 上述代码中 doubleTapFlag 用于标记双击发生,避免单击误触发。但更简洁的方式是直接使用 combinedClickable。

📊 手势决策流程 (SVG)

点击事件发生 300ms内 再次点击? 是 双击 否 单击 超时后触发单击,双击时取消单击

🏆 最佳实践 · 中小学生色系小贴士

场景推荐方案延迟
仅需双击detectTapGestures(onDoubleTap = {})无延迟
单击 + 双击combinedClickable (官方)单击延迟 ~300ms
自定义时序pointerInput + 时间戳标记可控
避免冲突使用 onDoubleTap 标记,onTap 中判断可优化

🎨 设计理念: 双击是富有节奏感的交互,适合点赞、缩放、收藏等场景。在中小学生风格的 UI 中,双击反馈可以搭配可爱的震动或颜色变化,提升趣味性。