如何检测撰写按钮上的运动事件?

How to detect motion events on a compose button?

我正在尝试创建一个图标按钮,它在点击时调用 lambda,但如果用户按下按钮并按住它,那么 lambda 也应该以固定的时间间隔连续调用。

@Composable
fun MyIconButton(
    someLambda: () -> Unit
) {
    IconButton(onClick = someLambda) {
        Icon(
            // painter and content description
        )
    }
}

我想要的是当用户按下按钮时,someLambda 应该被调用(工作正常)。此外,我还想重复调用 someLambda(两次调用之间有 500 毫秒的间隔),直到用户释放按钮。

基本上我想要的是检测诸如 KeyUp 和 KeyDown 事件之类的东西。

如何实现?

我会在明天更新答案,但现在,这应该适合您的用例

Modifier.pointerInput(Unit) {
    detectTapGestures(
        onPress = { /* Called when the gesture starts */ },
        onDoubleTap = { /* Called on Double Tap */ },
        onLongPress = { /* Called on Long Press */ },
        onTap = { /* Called on Tap */ }
    )
}

您可以为此使用 Modifier.pointerInpteropFilter

var job by remember {
    mutableStateOf<Job?>(null)
}
val scope = rememberCoroutineScope()

Icon(
    imageVector = Icons.Filled.Favorite,
    modifier = Modifier
        .requiredSize(96.dp)
        .pointerInteropFilter {
            when (it.action) {
                MotionEvent.ACTION_DOWN -> {
                    job = scope.launch {
                        while (true) {
                            // trigger event
                            Log.d("foo", "Trigger event")
                            delay(500L)
                        }
                    }
                }
                MotionEvent.ACTION_UP,
                MotionEvent.ACTION_CANCEL -> {
                    job?.cancel()
                    job = null
                }
            }
            true
        },
    contentDescription = "Sample icon"
)

另一个解决方案是使用 Modifier.pointerInput:

val scope = rememberCoroutineScope()
Icon(
    imageVector = Icons.Filled.Favorite,
    modifier = Modifier
        .requiredSize(96.dp)
        .pointerInput(Unit) {
            while (true) {
                awaitPointerEventScope {
                    awaitFirstDown()
                    val job = scope.launch {
                        while (true) {
                            // trigger event
                            Log.d("foo", "Trigger event")
                            delay(500L)
                            Log.d("foo", "After delay")
                        }
                    }
                    waitForUpOrCancellation()
                    job.cancel()
                }
            }
        },
    contentDescription = "Sample icon"
)

我在 Icon 上使用 Modifier.pointerInput 解决了问题。

Modifier.pointerInput(true) {
    detectTapGestures(onPress = {
        coroutineScope {
            val job = launch {
                while (true) {
                    // Invoke lambda
                    delay(500)
                }
            }
            tryAwaitRelease()
            job.cancel()
        }
    })
}

根据文档,

onPress is called when the press is detected and PressGestureScope.tryAwaitRelease can be used to detect when pointers have released or the gesture was canceled.