如何在Jetpack Compose中执行触觉反馈

23

如何在使用 Jetpack Compose 编写的点击事件中执行触觉反馈。我是 Jetpack Compose 的新手。 以下是我尝试过的方法 -

使用 Jetpack Compose,为了一个点击事件如何执行触觉反馈。

val hapticFeedback = LocalHapticFeedback

@Composable
fun Tab() {
    Row() {
        Icon(imageVector = icon, contentDescription = text)
        if (selected) {
            // i tried both the following ways, none are working. 
            hapticFeedback.current.performHapticFeedback(
                HapticFeedbackType(10)
            )
            hapticFeedback.current.performHapticFeedback(HapticFeedbackType.TextHandleMove)
....
            Spacer(Modifier.width(12.dp))
            Text(text.uppercase(Locale.getDefault()))
        }
    }
}

我能看见被选中的文本,但没有获得微妙的震动反馈。

5个回答

34
在Compose的版本rc-01中,您只能使用两种类型的触觉反馈:HapticFeedbackType.LongPress或HapticFeedbackType.TextHandleMove。
val haptic = LocalHapticFeedback.current
Row(
    Modifier.clickable {
        haptic.performHapticFeedback(HapticFeedbackType.LongPress)
    }
)

HapticFeedbackType.TextHandleMove 似乎在执行可点击操作时无法工作,只有 HapticFeedbackType.LongPress 起作用。 - Samrat
5
它根本不起作用。 - mr.icetea
显然,如果您使用Modifier.clickable,则Modifier.pointerInput()将无法正常工作。我有一些需要在pointerInput中执行的逻辑。有什么解决方法吗? - Opr Vld
1
Context是什么意思? - undefined

23

目前(Compose UI 1.1.0-beta03)仅支持通过LongPressTextHandleMove实现。

val haptic = LocalHapticFeedback.current
Button(onClick = {
    haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}) { ... }

正如@nglauber的回答所说。

我猜这是因为Compose Desktop具有多平台支持。

但是,如果您在Android上并且不需要Compose Desktop兼容性,则还有另一种方法可以很容易地使用它:

val view = LocalView.current
Button(onClick = {
    view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
}) { ... }

HapticFeedbackConstants 类有许多常量


9

在我的手机(以及我测试过的其他设备)上,LongPressTextHandleMove都无法使手机振动。

我们在转换到Compose之前这样解决了这个问题:

import android.content.Context
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.accessibility.AccessibilityManager

fun View.vibrate() = reallyPerformHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
fun View.vibrateStrong() = reallyPerformHapticFeedback(HapticFeedbackConstants.LONG_PRESS)

private fun View.reallyPerformHapticFeedback(feedbackConstant: Int) {
    if (context.isTouchExplorationEnabled()) {
        // Don't mess with a blind person's vibrations
        return
    }
    // Either this needs to be set to true, or android:hapticFeedbackEnabled="true" needs to be set in XML
    isHapticFeedbackEnabled = true

    // Most of the constants are off by default: for example, clicking on a button doesn't cause the phone to vibrate anymore
    // if we still want to access this vibration, we'll have to ignore the global settings on that.
    performHapticFeedback(feedbackConstant, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
}

private fun Context.isTouchExplorationEnabled(): Boolean {
    // can be null during unit tests
    val accessibilityManager = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager?
    return accessibilityManager?.isTouchExplorationEnabled ?: false
}

目前我们仍需使用此代码,并像Daniele Segato的回答中那样从Compose中访问它:

@Composable
fun VibratingButton() {
    val view = LocalView.current
    Button(onClick = {
        view.vibrate()
    }) { ... }
}


1
这是正确的答案。 - mr.icetea

4

对我来说,当用户按下按钮时,这个方法很有效。使用Compose 1.2.0-beta01

val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()

val hapticFeedback = LocalHapticFeedback.current
LaunchedEffect(key1 = isPressed) {
    if (isPressed) {
        hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
    }
}

这是最佳答案。请注意,这仅在您的安卓设置中启用触觉反馈时才有效。 - dessalines

-4

将反馈逻辑添加到应用于RowModifier.clickable {...}内部


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接