HarmonyOS vibrator API 封装解析:DeviceUtil 振动工具函数从入门到实战
文章目录
- 一、前言
- 二、工具函数方法
- 三、方法详解
- 3.1 `startVibration(duration, usage)` — 开启振动
- 3.2 `stopVibration()` — 停止振动
- 四、完整 Demo 演示代码
- 4.1 振动控制方法
- 4.2 UI 渲染
- 4.3 API 列表数据
- 五、运行效果说明
- 六、实际开发建议
- 场景 1:操作确认反馈
- 场景 2:游戏碰撞反馈
- 场景 3:来电振动
- 七、常见错误处理
- 八、小结
一、前言
近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦
案例demo导航展示
↓↓↓↓↓↓接下来言归正传 ↓↓↓↓
振动反馈是移动应用中重要的交互手段之一,合理的振动反馈能大幅提升用户体验——比如消息通知、操作确认、游戏特效、来电提醒等场景。HarmonyOS 提供了vibrator模块来控制设备振动,DeviceUtil对其进行了封装,只需两个方法即可完成所有振动控制。
二、工具函数方法
// 开启振动(需要权限:ohos.permission.VIBRATE)staticstartVibration(duration:number=1000,usage:vibrator.Usage='media'):Promise<void>// 停止振动(按照 VIBRATOR_STOP_MODE_TIME 模式)staticstopVibration():Promise<void>三、方法详解
3.1startVibration(duration, usage)— 开启振动
源码:
staticstartVibration(duration:number=1000,usage:vibrator.Usage='media'):Promise<void>{returnvibrator.startVibration({type:'time',duration:duration},{id:0,usage:usage});}参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
duration | number | 1000 | 振动时长,单位毫秒(ms) |
usage | vibrator.Usage | 'media' | 振动使用场景 |
usage参数可选值:
| 值 | 适用场景 |
|---|---|
'media' | 媒体播放、视频、音乐 |
'ringtone' | 来电铃声 |
'alarm' | 闹钟 |
'notification' | 通知 |
'communication' | 通话 |
'touch' | 触摸反馈 |
'unknown' | 未知场景 |
底层原理:
调用vibrator.startVibration时使用了{ type: 'time', duration: duration }这种按时长振动的模式(区别于按振动效果模式type: 'preset')。id: 0表示使用默认振动器。
权限要求:
使用振动功能前必须在module.json5中声明权限:
{"requestPermissions":[{"name":"ohos.permission.VIBRATE"}]}3.2stopVibration()— 停止振动
源码:
staticstopVibration():Promise<void>{returnvibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_TIME);}说明:
使用VIBRATOR_STOP_MODE_TIME模式停止振动,该模式与startVibration中的{ type: 'time' }对应,停止的是按时长方式启动的振动。
四、完整 Demo 演示代码
DeviceUtilDemoPage.ets中振动演示部分的完整代码:
4.1 振动控制方法
// ── 振动 ─────────────────────────────────────────────doVibrate(duration:number){this.vibrationStatus=`振动中 (${duration}ms)`;this.vibrationColor='#00C853';this.addLog('Vibrate',`开始振动${duration}ms...`,'info');DeviceUtil.startVibration(duration,'media').then(()=>{this.vibrationStatus='待机';this.vibrationColor='#888';this.addLog('Vibrate',`振动结束`,'success');}).catch((e:Error)=>{this.vibrationStatus='振动失败';this.vibrationColor='#FF5252';this.addLog('Vibrate',`振动失败:${e.message}`,'error');});}stopVibrate(){DeviceUtil.stopVibration().then(()=>{this.vibrationStatus='已停止';this.vibrationColor='#FF9800';this.addLog('Vibrate','振动已停止','warn');}).catch((e:Error)=>{this.addLog('Vibrate',`停止失败:${e.message}`,'error');});}4.2 UI 渲染
// ══ 振动 ══════════════════════════════════════════════if(this.activeTab===4){Column(){Text('振动演示').fontSize(13).fontColor('#666').fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})Text('startVibration(duration, usage) / stopVibration()').fontSize(11).fontColor('#888').alignSelf(ItemAlign.Start).margin({bottom:12})// 状态显示Row(){Text('状态:').fontSize(14).fontColor('#888')Text(this.vibrationStatus).fontSize(14).fontWeight(FontWeight.Bold).fontColor(this.vibrationColor).margin({left:8})}.width('100%').margin({bottom:16})Text('振动时长选择').fontSize(12).fontColor('#888').alignSelf(ItemAlign.Start).margin({bottom:8})Flex({wrap:FlexWrap.Wrap}){Button('短振 100ms').fontSize(12).height(36).backgroundColor('#4080FF').fontColor('#FFF').onClick(()=>{this.doVibrate(100);}).margin({right:8,bottom:8})Button('中振 500ms').fontSize(12).height(36).backgroundColor('#00C853').fontColor('#FFF').onClick(()=>{this.doVibrate(500);}).margin({right:8,bottom:8})Button('长振 1000ms').fontSize(12).height(36).backgroundColor('#FF9800').fontColor('#FFF').onClick(()=>{this.doVibrate(1000);}).margin({right:8,bottom:8})Button('超长振 3000ms').fontSize(12).height(36).backgroundColor('#FF5252').fontColor('#FFF').onClick(()=>{this.doVibrate(3000);}).margin({right:8,bottom:8})}.width('100%').margin({bottom:12})Button('停止振动 stopVibration()').width('100%').height(40).borderRadius(10).backgroundColor('#D63384').fontColor('#FFF').fontSize(13).onClick(()=>{this.stopVibrate();})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)// API 说明Column(){Text('Vibration API').fontSize(13).fontColor('#666').fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:8})ForEach(this.getVibrationApiList(),(row:VibrationApiItem)=>{Row(){Text(row.name).fontSize(11).fontFamily('monospace').fontColor('#D63384').width(140).maxLines(1)Text(row.desc).fontSize(11).fontColor('#666').layoutWeight(1)}.width('100%').padding({top:4,bottom:4})},(row:VibrationApiItem)=>row.name)}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)}4.3 API 列表数据
getVibrationApiList():VibrationApiItem[]{return[{name:'startVibration(ms, usage)',desc:'开启振动,usage 支持 media/ringtone/alarm/notification'},{name:'stopVibration()',desc:'按 TIME 模式停止振动'},];}五、运行效果说明
Demo 中提供了 4 个时长按钮:
- 短振 100ms:适合触摸反馈、按钮点击确认
- 中振 500ms:适合操作成功提示
- 长振 1000ms:适合消息通知
- 超长振 3000ms:适合来电铃声场景
振动状态实时显示:
- 振动中:绿色"振动中 (Xms)"
- 待机:灰色"待机"
- 已停止:橙色"已停止"
- 失败:红色"振动失败"
六、实际开发建议
场景 1:操作确认反馈
Button('提交订单').onClick(async()=>{try{awaitsubmitOrder();// 成功:短振提示awaitDeviceUtil.startVibration(100,'touch');promptAction.showToast({message:'提交成功!'});}catch(e){// 失败:双击振动awaitDeviceUtil.startVibration(200,'notification');promptAction.showToast({message:'提交失败,请重试'});}})场景 2:游戏碰撞反馈
onCollision(){DeviceUtil.startVibration(300,'media');}场景 3:来电振动
onIncomingCall(){DeviceUtil.startVibration(2000,'ringtone');}onCallAnswered(){DeviceUtil.stopVibration();}七、常见错误处理
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 201 | 权限被拒绝 | 在module.json5中申请ohos.permission.VIBRATE |
| 401 | 参数错误 | 检查 duration 是否为正整数,usage 是否合法 |
| 801 | 设备不支持振动 | 使用canIUse检测能力后再调用 |
| 14600101 | 设备操作失败 | 重试或降级处理 |
八、小结
DeviceUtil的振动功能封装极为简洁:
| 方法 | 返回值 | 说明 |
|---|---|---|
startVibration(duration, usage) | Promise<void> | 按时长启动振动 |
stopVibration() | Promise<void> | 停止 TIME 模式振动 |
记住两点:
- 必须申请
VIBRATE权限,否则会收到201错误。 - 使用
.then().catch()或async/await,振动是异步操作,结果在 Promise 中返回。
合理使用振动反馈,能让你的应用在交互细节上更加出色,让用户感受到精心设计的产品质感。
