Android 设备上最常见的振动执行器是线性谐振执行器 (LRA)。LRA 在原本无响应的玻璃表面上模拟按钮点击的感觉。清晰且干脆的点击反馈信号通常持续 10 到 20 毫秒。这种感觉使用户交互感觉更自然。对于虚拟键盘,这种点击反馈可以提高打字速度并减少错误。
LRA 有几个常见的谐振频率
- 一些 LRA 的谐振频率范围在 200 到 300 赫兹之间,这与人皮肤对振动最敏感的频率一致。在此频率范围内的振动感觉通常被描述为平滑、尖锐和穿透力强。
- 其他型号的 LRA 的谐振频率较低,约为 150 赫兹。感觉上更柔和、更饱满(在维度上)。
在两个不同频率下输入相同的电压,振动输出振幅可能不同。频率距离 LRA 的谐振频率越远,其振动振幅越低。
特定设备的触觉效果同时使用振动执行器及其驱动程序。包含过驱动和主动制动功能的触觉驱动程序可以减少 LRA 的上升时间和振铃,从而实现更灵敏和清晰的振动。
振动器输出加速度
频率-输出加速度映射 (FOAM) 描述了在给定振动频率(单位:赫兹)下可达到的最大输出加速度(单位:G 峰值)。从 Android 16 (API level 36) 开始,平台通过 VibratorFrequencyProfile
内置支持此映射。您可以将此类别与基本和高级包络线 API 一起使用,以创建触觉效果。
大多数 LRA 电机在其 FOAM 中都有一个峰值,通常接近其谐振频率。当频率偏离此范围时,加速度通常呈指数下降。曲线可能不对称,并且可能在谐振频率附近出现平台,以保护电机免受损坏。
旁边图表显示了一个 LRA 电机的 FOAM 示例。
人感知检测阈值
人感知检测阈值是指一个人能够可靠地检测到的振动的最小加速度。此阈值水平随振动频率而变化。
旁边图表显示了人类触觉感知检测阈值(以加速度为单位),作为时间频率的函数。阈值数据转换自 Bolanowski Jr., S. J. 等人 1988 年发表的论文"Four channels mediate the mechanical aspects of touch." 图 1 中的位移阈值。
Android 在 BasicEnvelopeBuilder
中自动处理此阈值,它会验证所有效果使用的频率范围产生的振动振幅至少超过人感知检测阈值 10 dB。
在线教程进一步解释了加速度振幅和位移振幅之间的转换。
振动加速度水平
人对振动强度的感知(一种感知度量)不会随振动振幅(一种物理参数)线性增长。感知强度由感觉水平 (SL) 表征,其定义为在相同频率下高于检测阈值的 dB 值。
相应的振动加速度振幅(单位:G 峰值)可以按如下方式计算:
...其中振幅 dB 是 SL 和检测阈值之和——在特定频率下,这是旁边图表中纵轴上的值。
旁边图表显示了 10、20、30、40 和 50 dB SL 的振动加速度水平,以及人触觉感知检测阈值 (0 dB SL),作为时间频率的函数。数据估算自 Verrillo, R. T. 等人 1969 年发表的论文"Sensation magnitude of vibrotactile stimuli." 图 8。
Android 在 BasicEnvelopeBuilder
中自动处理此转换,它将感觉水平空间 (dB SL) 中的标准化强度值转换为输出加速度。另一方面,WaveformEnvelopeBuilder
不应用此转换,而是将值作为加速度空间 (Gs) 中的标准化输出加速度振幅。包络线 API 假定,当设计人员或开发者考虑振动强度的变化时,他们期望感知的强度遵循分段线性包络线。
设备上的默认波形平滑处理
为了说明,请考虑自定义波形模式在通用设备上的行为:
Kotlin
val timings: LongArray = longArrayOf(50, 50, 50, 50, 50, 100, 350, 250)
val amplitudes: IntArray = intArrayOf(77, 79, 84, 99, 143, 255, 0, 255)
val repeatIndex = -1 // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))
Java
long[] timings = new long[] { 50, 50, 50, 50, 50, 100, 350, 250 };
int[] amplitudes = new int[] { 77, 79, 84, 99, 143, 255, 0, 255 };
int repeatIndex = -1 // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));
以下图表显示了与上述代码片段对应的输入波形和输出加速度。请注意,每当模式中出现振幅阶跃变化时——即在 0ms、150ms、200ms、250ms 和 700ms 时——加速度都会逐渐增加,而不是突然增加。每次振幅阶跃变化时都会出现过冲,并且当输入振幅突然降至 0 时,会出现持续至少 50ms 的可见振铃。
改进的触觉模式
为了避免过冲并减少振铃时间,请更平缓地改变振幅。以下显示了修订版的波形图和加速度图:
Kotlin
val timings: LongArray = longArrayOf(
25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
300, 25, 25, 150, 25, 25, 25
)
val amplitudes: IntArray = intArrayOf(
38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
0, 85, 170, 255, 170, 85, 0
)
val repeatIndex = -1 // Do not repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))
Java
long[] timings = new long[] {
25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
300, 25, 25, 150, 25, 25, 25
};
int[] amplitudes = new int[] {
38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
0, 85, 170, 255, 170, 85, 0
};
int repeatIndex = -1; // Do not repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));
创建更复杂的触觉效果
令人满意的点击响应中的其他元素更为复杂,需要了解设备中使用的 LRA。为了获得最佳效果,请使用设备预制波形和平台提供的常量,这些常量让您可以执行以下操作:
- 执行清晰的效果和基元。
- 连接它们以组成新的触觉效果。
这些预定义的触觉常量和基元可以极大地加快您创建高质量触觉效果的工作速度。