鸿蒙新特性:@ohos.vibrator 触感反馈引擎实战
前言
触感反馈(Haptic Feedback)是现代移动设备交互体验的重要组成部分。从键盘按键的轻微振动到闹钟的持续提醒,从游戏中的碰撞反馈到通知到达时的短震,线性马达驱动的高品质振动已经成为区分设备档次的关键指标。
HarmonyOS 通过 @ohos.vibrator 模块为开发者提供了完整的振动马达控制能力。该模块封装了从简单的时长振动到复杂的预设效果、从振动用途分类到模式停止控制的全套 API。与 Android 的 Vibrator 服务相比,HarmonyOS 的 API 设计更加现代化——使用类型化的 VibrateEffect 替代原始数字参数,使用 Usage 分类让系统智能调度振动资源。
本文通过一个可交互的 触感反馈实验室 Demo,深入讲解 @ohos.vibrator 的全部核心 API,涵盖预设效果、自定义时长、序列组合和振动控制四大功能模块。读者可将 Demo 安装到真机上,亲身体验不同振动效果的差异。
环境与权限
模块导入
import vibrator from '@ohos.vibrator';
vibrator 模块属于 @kit.SensorServiceKit,使用 default export 方式导出。
权限声明
振动功能需要 ohos.permission.VIBRATE 权限,该权限属于 normal 级别,无需用户手动授权,声明即可使用。在 module.json5 中配置:
"requestPermissions": [
{
"name": "ohos.permission.VIBRATE",
"reason": "$string:vibrate_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
如果未声明该权限,调用任何 startVibration() 方法都会抛出 BusinessError 201(权限拒绝)异常。在封装振动调用时,务必包裹 try-catch 以提供用户友好的降级体验。
核心 API 模型
@ohos.vibrator 的 API 设计围绕三个核心概念展开:
- VibrateEffect — 描述"怎么振":时长(time)、预设(preset)、来自文件(file)、自定义模式(pattern)
- VibrateAttribute — 描述"为什么振":用途分类(usage)、马达 ID(id)、设备 ID(deviceId)
- VibratorStopMode — 描述"怎么停":按时间停止(time)或按预设停止(preset)
这种设计将振动描述与振动意图解耦,让系统可以根据 usage 参数智能分配振动资源——例如来电铃声(alarm)的振动优先级高于 UI 触感(touch)。
startVibration — 启动振动
function startVibration(
effect: VibrateEffect,
attribute: VibrateAttribute
): Promise<void>
这是 API 9 引入的核心方法,替代了早期已废弃的 vibrate() 函数。它接受两个参数:振动效果和振动属性,返回 Promise。
stopVibration — 停止振动
function stopVibration(stopMode: VibratorStopMode): Promise<void>
function stopVibration(): Promise<void>
function stopVibrationSync(): void
三种停止模式:按模式停止、停止所有异步、停止所有同步。stopVibrationSync() 是 API 12 新增的无参数方法,可立即停止所有类型的振动,无需传入 stopMode。
isSupportEffect / isSupportEffectSync — 检测支持
function isSupportEffect(effectId: string): Promise<boolean>
function isSupportEffectSync(effectId: string): boolean
检测设备是否支持某个预设振动效果。不同设备的线性马达硬件能力不同,部分效果可能不可用。建议在触发预设效果前先检测。
VibrateEffect 详解
VibrateEffect 是一个联合类型,包含四种振动效果描述方式。
1. VibrateTime — 时长振动
最简单的振动形式,按指定时长持续振动。适合简单的触感反馈场景。
interface VibrateTime {
type: 'time';
duration: number; // 振动时长(毫秒)
}
// 示例:振动 500ms
vibrator.startVibration(
{ type: 'time', duration: 500 },
{ usage: 'touch' }
);
duration 的有效范围建议在 10ms 到 5000ms 之间。太短(<10ms)人无法感知,太长(>5s)可能被系统截断或触发过热保护。
2. VibratePreset — 预设效果
HarmonyOS 内置了一系列预设振动效果,这些效果由系统根据设备马达硬件特性自动优化,通常比手动设置时长能获得更好的触感体验。
interface VibratePreset {
type: 'preset';
effectId: string; // 预设效果 ID
count: number; // 重复次数
intensity?: number; // 强度系数(1-5,默认 5)
}
// 示例:触发成功通知效果
vibrator.startVibration(
{ type: 'preset', effectId: 'haptic.notice.success', count: 1 },
{ usage: 'notification' }
);
HapticFeedback 枚举值
API 12 引入了 HapticFeedback 枚举,定义了一套简单通用的振动效果:
| 枚举成员 | effectId 字符串 | 描述 |
|---|---|---|
EFFECT_SOFT |
'haptic.effect.soft' |
轻柔振动,适合轻微交互反馈 |
EFFECT_HARD |
'haptic.effect.hard' |
强烈振动,适合物理按键模拟 |
EFFECT_SHARP |
'haptic.effect.sharp' |
尖锐振动,适合短触感提示 |
EFFECT_NOTICE_SUCCESS |
'haptic.notice.success' |
成功通知,短振+上升感 |
EFFECT_NOTICE_FAILURE |
'haptic.notice.fail' |
失败通知,双振+下沉感 |
EFFECT_NOTICE_WARNING |
'haptic.notice.warning' |
警告通知,长振+间隔重复 |
此外还有 EFFECT_CLOCK_TIMER(EffectId 枚举,值为 'haptic.clock.timer'),专门用于计时器调节场景的振动反馈。
effectId 字符串 vs 枚举
注意 SDK 中的 effectId 是 string 类型而非枚举值。HapticFeedback.EFFECT_SOFT 只是一个值为 'haptic.effect.soft' 的字符串常量。在代码中直接使用字符串 'haptic.effect.soft' 或 vibrator.HapticFeedback.EFFECT_SOFT 均可,效果相同。
3. VibrateFromFile — 自定义效果文件
对于需要高度定制振动曲线的应用(如游戏),可以通过 JSON 或特定格式文件定义振动效果:
interface VibrateFromFile {
type: 'file';
hapticFd: HapticFileDescriptor; // 效果文件的文件描述符
}
这种方式需要先读取自定义效果文件,将文件的 HapticFileDescriptor 传入。实际开发中较少使用,一般预设效果已能满足大部分需求。
4. VibrateFromPattern — Builder 模式(API 18+)
API 18 引入了 VibratorPatternBuilder,用于编程式构建复杂的振动事件序列:
let builder = new vibrator.VibratorPatternBuilder();
builder.addTransientEvent(200, {}); // 在 200ms 处触发瞬时振动
builder.addContinuousEvent(500, 300, {}); // 在 500ms 处开始 300ms 的持续振动
let pattern: vibrator.VibratorPattern = builder.build();
vibrator.startVibration(
{ type: 'pattern', pattern: pattern },
{ usage: 'physicalFeedback' }
);
VibratorPatternBuilder 支持 addTransientEvent(time, options) 和 addContinuousEvent(time, duration, options) 两种事件类型,分别对应瞬时振动和持续振动。通过组合不同的事件类型和时间点,可以精确编排振动节奏。

VibrateAttribute 详解
Usage — 振动用途分类
Usage 是 VibrateAttribute 中最关键的属性,它告诉系统这次振动的目的,让系统可以做出智能调度决策:
type Usage = 'unknown' | 'alarm' | 'ring' | 'notification' |
'communication' | 'touch' | 'media' |
'physicalFeedback' | 'simulateReality';
| 值 | 含义 | 典型场景 | 优先级 |
|---|---|---|---|
'alarm' |
闹钟 | 起床闹钟、计时器到期 | 高 |
'ring' |
来电铃声 | 电话、视频通话来电 | 高 |
'notification' |
通知 | 消息推送、邮件提醒 | 中 |
'communication' |
通讯 | 短信、即时消息 | 中 |
'touch' |
触控反馈 | 按钮点击、滑动反馈 | 低 |
'media' |
媒体 | 音乐、视频播放中的振动 | 低 |
'physicalFeedback' |
物理反馈 | 游戏、模拟实体的触感 | 中 |
'simulateReality' |
虚拟现实 | AR/VR 场景中的触感模拟 | 中 |
'unknown' |
未知 | 未分类的振动用途 | 低 |
实际影响:当系统检测到多个振动请求并发时,会按优先级决定哪个振动执行。例如闹钟响铃期间,触控反馈的振动会被降级或忽略。
完整示例
let attribute: vibrator.VibrateAttribute = {
usage: 'alarm', // 必须,声明振动用途
id: 0, // 可选,马达 ID(默认 0)
deviceId: undefined // 可选,设备 ID(默认本地设备)
};
通常只需要设置 usage,其余参数使用默认值即可。
VibratorStopMode 详解
enum VibratorStopMode {
VIBRATOR_STOP_MODE_TIME = 'time',
VIBRATOR_STOP_MODE_PRESET = 'preset'
}
VIBRATOR_STOP_MODE_TIME(‘time’):停止由时长触发的一次性振动VIBRATOR_STOP_MODE_PRESET(‘preset’):停止由预设效果触发的振动
如果使用 stopVibration() 无参数版本(API 10+),则无需关心停止模式,直接停止所有类型的振动。API 12 新增的 stopVibrationSync() 更是提供了同步停止的能力,适合在页面销毁(aboutToDisappear)等同步上下文中使用。
Demo:触感反馈实验室
我们构建了一个功能完整的触感反馈体验工具,用户可在真机上亲身感受不同振动效果的差异。
功能模块
-
预设效果网格 — 7 种预设振动(轻柔/强烈/尖锐/成功/失败/警告/计时器),以 4 列网格布局展示,点击即可触发。配合重复次数调节器(1-10 次),可测试多次重复振动
-
自定义时长振动 — 通过滑块选择振动时长(50ms-3000ms),切换八种振动用途分类,一键触发。底部提示文字解释 Usage 参数的调度意义
-
组合振动序列 — 两个预设序列按钮:轻→强→尖(质感序列)和成功→警告→失败(通知序列),通过
setTimeout串联多个startVibration调用实现振动组合 -
实时状态面板 — 显示最近触发的效果名称、马达支持状态、权限要求、停止模式等运行信息
-
紧急停止按钮 — 常驻顶部状态栏,红色醒目样式,调用
stopVibrationSync()立即终止所有振动
核心实现:检测马达支持
checkSupport(): void {
try {
this.isSupported = vibrator.isSupportEffectSync('haptic.effect.soft')
? '支持' : '不支持';
} catch (e) {
this.isSupported = '检测失败';
}
}
使用同步 API isSupportEffectSync() 在页面初始化时检测马达硬件状态。检测失败通常意味着设备不具备线性马达(如部分平板设备)。
核心实现:触发预设效果
triggerPresetEffect(item: PresetEffect): void {
try {
vibrator.startVibration(
{ type: 'preset', effectId: item.effectId, count: this.vibrateCount },
{ usage: item.usage }
);
this.statusMsg = '已触发: ' + item.name + ' x' + this.vibrateCount.toString();
} catch (e) {
this.statusMsg = '触发失败: 请确认已授予振动权限';
}
}
VibratePreset 的三个参数:
type: 'preset'— 指定为预设效果模式effectId— 预设效果的字符串 IDcount— 重复次数,帮助用户体验连续振动模式(如紧急通知连续震 3 次)
核心实现:自定义时长振动
triggerTimeVibration(): void {
try {
vibrator.startVibration(
{ type: 'time', duration: this.duration },
{ usage: this.usageValues[this.usageIndex] }
);
this.statusMsg = '时长振动: ' + this.duration.toString() + 'ms ('
+ this.usageLabels[this.usageIndex] + ')';
} catch (e) {
this.statusMsg = '触发失败: 请确认已授予振动权限';
}
}
VibrateTime 只需要两个参数:type: 'time' 和 duration(毫秒)。配合 usage 属性让系统了解振动目的。
核心实现:振动序列
playSequence(): void {
try {
// 第一步:轻柔振动
vibrator.startVibration(
{ type: 'preset', effectId: 'haptic.effect.soft', count: 1 },
{ usage: 'physicalFeedback' }
);
// 250ms 后第二步:强烈振动
setTimeout(() => {
vibrator.startVibration(
{ type: 'preset', effectId: 'haptic.effect.hard', count: 1 },
{ usage: 'physicalFeedback' }
);
// 300ms 后第三步:尖锐振动
setTimeout(() => {
vibrator.startVibration(
{ type: 'preset', effectId: 'haptic.effect.sharp', count: 1 },
{ usage: 'physicalFeedback' }
);
}, 300);
}, 250);
this.statusMsg = '播放序列: 轻柔 → 强烈 → 尖锐';
} catch (e) {
this.statusMsg = '播放失败: 请授予振动权限';
}
}
通过 setTimeout 串联多个振动调用,实现自定义的振动序列组合。间隔时间需要根据实际效果调试——太短会产生重叠,太长则有明显停顿感。
核心实现:同步停止
stopAllVibration(): void {
try {
vibrator.stopVibrationSync();
this.statusMsg = '振动已停止';
} catch (e) {
this.statusMsg = '停止失败';
}
}
使用 stopVibrationSync() 代替 stopVibration() 的原因:同步版本无需 callback/Promise,代码更简洁,适合在页面即将销毁等需要在同步上下文中立即停止的场景。
枚举值与 SDK 版本对应关系
本 Demo 使用的 API 版本跨度较大(API 9-12),整理如下:
| API | 内容 |
|---|---|
| EffectId | API 8,已废弃(仅保留 EFFECT_CLOCK_TIMER) |
| startVibration | API 9,替代 vibrate() |
| VibrateEffect = VibrateTime | VibratePreset | API 9 |
| VibrateAttribute | API 9 |
| vibrate() — 废弃 | API 8,API 9 起弃用 |
| VibrateFromFile | API 10 |
| stopVibration() 无参数版 | API 10 |
| isSupportEffectSync / stopVibrationSync | API 12 |
| HapticFeedback 枚举 | API 12 |
| VibratorPatternBuilder | API 18 |
在 API 24 环境下,建议使用 startVibration() + VibrateEffect + VibrateAttribute 的标准组合,废弃的 vibrate() 函数不再推荐使用。
最佳实践
1. 始终包裹 try-catch
振动权限可能被用户拒绝(某些 ROM 可关闭),马达硬件可能异常。对每个振动调用包裹 try-catch 确保不影响主流程:
try {
vibrator.startVibration({ type: 'time', duration: 200 }, { usage: 'touch' });
} catch (e) {
// 静默降级:无振动不影响功能
}
2. 选择合适的 Usage
不恰当的 Usage 会导致振动被系统抑制。关键规则:
- UI 交互反馈 →
'touch'(按钮点击、开关切换等) - 消息通知 →
'notification' - 紧急提醒 →
'alarm'或'ring' - 游戏/模拟 →
'physicalFeedback'或'simulateReality'
错误示例:用 'alarm' 做按钮点击反馈——闹钟的振动强度通常很大,会让用户感到不适。
3. 控制振动时长和频率
- 单次不超过 3 秒:连续振动超过 3 秒在用户体验上通常是负面的
- 间隔不小于 100ms:过于密集的振动会糊成一团,失去层次感
- 重复次数合理:预设效果的
count参数不要超过 5,特别是报警类效果
4. 页面销毁时停止振动
在 aboutToDisappear 生命周期中停止振动,避免页面退出后振动仍在进行:
aboutToDisappear(): void {
try {
vibrator.stopVibrationSync();
} catch (e) {
// 静默处理
}
}
5. 检测马达能力
在应用启动时检测马达能力,根据设备差异提供降级体验:
let hasHaptic: boolean = vibrator.isSupportEffectSync('haptic.effect.soft');
if (!hasHaptic) {
// 使用视觉反馈替代触感反馈(如闪烁、颜色变化)
}
6. 避免在主线程大量调用
虽然 startVibration() 返回 Promise,但底层 IPC 调用是异步的,频繁调用(如滚动列表中每个 item 触发振动)会导致性能问题。建议设置最小触发间隔(如 300ms debounce)。
与 Android Vibrator API 对比
| 特性 | HarmonyOS | Android |
|---|---|---|
| 基础 API | startVibration(effect, attr) |
vibrator.vibrate(VibrationEffect) |
| 时长振动 | { type: 'time', duration } |
VibrationEffect.createOneShot(millis, amplitude) |
| 预设效果 | { type: 'preset', effectId, count } |
VibrationEffect.createPredefined(id) |
| 用途分类 | usage: 'alarm' | 'ring' | ... |
AudioAttributes.USAGE_* |
| 停止方式 | stopVibrationSync() 同步 / stopVibration() 异步 |
vibrator.cancel() |
| 权限 | ohos.permission.VIBRATE (normal) |
android.permission.VIBRATE (normal) |
| 自定义模式 | VibratorPatternBuilder (API 18+) |
VibrationEffect.createWaveform(timings, amplitudes, repeat) |
HarmonyOS 的优势在于 Usage 分类更加细粒度(8 种场景),且使用类型化对象替代 Android 的原始数组参数,代码可读性更好。Android 的自定义波形支持更早(API 26),HarmonyOS 的 VibratorPatternBuilder 直到 API 18 才引入。
线性马达硬件基础
理解 API 后,了解硬件特性有助于撰写更精细的振动体验:
- X 轴线性马达:振动方向沿设备短轴,振感紧凑,响应快(通常 <10ms 起振),多用于旗舰手机
- Z 轴线性马达:振动方向沿设备厚度,振感偏"弹跳",响应较慢
- ERM(偏心转子马达):传统方案,通过旋转偏心轮产生振动,起振慢(>50ms),振感模糊
HarmonyOS 的预设效果(如 EFFECT_SOFT / EFFECT_HARD / EFFECT_SHARP)在 X 轴线性马达上表现最佳,各项差异明显。在 ERM 马达上这几个效果的差别会缩小。
总结
本文详细讲解了 HarmonyOS 振动马达控制的核心 API:
- startVibration(effect, attribute) — 启动振动,支持四种效果类型
- stopVibration / stopVibrationSync — 按模式或全部停止振动
- isSupportEffect / isSupportEffectSync — 检测马达硬件能力
- VibrateEffect — 联合类型:
VibrateTime|VibratePreset|VibrateFromFile|VibrateFromPattern - VibrateAttribute — 振动属性,核心是
usage(8 种场景分类) - HapticFeedback — 预设效果枚举(SOFT/HARD/SHARP + NOTICE_SUCCESS/FAIL/WARNING)
- VibratorPatternBuilder — Builder 模式构建复杂振动序列(API 18+)
触感反馈实验室 Demo 是一个实用的开发工具,展示了从简单到复杂的各类振动控制场景。读者可在真机上安装体验,直观感受不同振动效果和 Usage 参数的实际差异。对于需要构建高品质交互体验的应用,精心设计的触感反馈是不可忽视的细节竞争力。
更多推荐



所有评论(0)