Compose 中 Multitouch

69 阅读1分钟

在 Jetpack Compose 中,多点触控(Multitouch)允许用户使用多个手指同时在屏幕上进行交互,例如同时缩放、旋转或移动多个对象。虽然 Compose 本身并不直接提供多点触控的特定功能,但您可以通过使用底层的触摸事件来实现多点触控的功能。以下是一个示例代码,演示了如何在 Jetpack Compose 中实现多点触控的简单缩放功能:

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
import kotlin.math.min

@Composable
fun MultitouchExample() {
    var scale by remember { mutableStateOf(1f) }
    var previousDistance by remember { mutableStateOf(0f) }
    var previousOffset by remember { mutableStateOf(Offset.Zero) }

    Surface(modifier = Modifier.fillMaxSize()) {
        Canvas(modifier = Modifier.fillMaxSize()
            .pointerInput(Unit) {
                forEachGesture {
                    awaitPointerEventScope {
                        // 获取多指触控事件
                        val event = awaitPointerEvent()
                        val pointerCount = event.pointerCount
                        val pointers = event.changes
                            .filter { it.id != -1L } // 排除主指针

                        if (pointerCount >= 2) {
                            // 计算多指触摸中心点
                            val newOffset = pointers.fold(Offset.Zero) { acc, change ->
                                acc + change.position
                            } / pointerCount.toFloat()

                            // 计算两个触摸点之间的距离
                            val newDistance = pointers.fold(0f) { acc, change ->
                                acc + change.previousPosition.distanceTo(change.position)
                            } / pointerCount.toFloat()

                            if (previousDistance != 0f) {
                                // 更新缩放比例
                                scale *= newDistance / previousDistance
                                // 更新偏移量,使得缩放中心不变
                                previousOffset += (newOffset - previousOffset) * (1f - newDistance / previousDistance)
                            }

                            previousDistance = newDistance
                            previousOffset = newOffset
                        }
                    }
                }
            }) {
            scale(scale) {
                // 在画布上绘制一个缩放的矩形
                drawRect(
                    color = Color.Red,
                    topLeft = Offset(previousOffset.x - 50.dp.toPx(), previousOffset.y - 50.dp.toPx()),
                    size = androidx.compose.ui.geometry.Size(100.dp.toPx(), 100.dp.toPx())
                )
            }
        }
    }
}

在上述示例中,我们使用 Canvas 绘制了一个红色的矩形,并通过 pointerInput 监听多点触摸事件。在触摸事件处理程序中,我们计算了多个触摸点之间的距离,并根据距离的变化来实现缩放功能。通过同时跟踪多个触摸点,我们可以实现多点触控的功能,例如缩放、旋转等。