如何检测撰写按钮上的运动事件?
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.
我正在尝试创建一个图标按钮,它在点击时调用 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 andPressGestureScope.tryAwaitRelease
can be used to detect when pointers have released or the gesture was canceled.