当前位置: 首页 > news >正文

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});}

参数说明:

参数类型默认值说明
durationnumber1000振动时长,单位毫秒(ms)
usagevibrator.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 模式振动

记住两点:

  1. 必须申请VIBRATE权限,否则会收到201错误。
  2. 使用.then().catch()async/await,振动是异步操作,结果在 Promise 中返回。

合理使用振动反馈,能让你的应用在交互细节上更加出色,让用户感受到精心设计的产品质感。

http://www.jsqmd.com/news/900921/

相关文章:

  • 用Unity Embedded Browser插件打造混合应用:本地HTML图表(ECharts)与Unity 3D场景实时交互实战
  • ChatGPT能听懂巴赫赋格吗?:实测12款提示词模板,3分钟生成专业级和声分析报告(附MIT音乐认知实验室验证数据)
  • SLANeXt_wireless_onnx深度解析:革新表格识别的终极AI模型
  • ChatGPT写诗总像说明书?——从古典格律到自由诗体的12种结构化提示模板(含平仄校验与意象密度优化公式)
  • 数据主权时代:如何构建个人AI记忆中心的完整技术方案
  • 如何用Arduino-ESP32快速构建智能物联网设备:从入门到实战的完整指南
  • HarmonyOS 屏幕信息获取入门:getDefaultDisplaySync 与 getAllDisplays 详解
  • 用CloudCompare和Python处理DublinCityDataSet点云数据,我踩过的那些坑(附完整代码)
  • ppf-contact-solver故障排除:安装依赖冲突的终极解决指南
  • AdelaiDepth深度解析:从单张图像重建3D场景的完整指南
  • E5-small常见问题解答:解决使用过程中的10个典型问题
  • 别再拍脑袋定样本量了!用Excel手把手教你搞定市场调研问卷的样本容量(附置信区间计算模板)
  • 如何永久保存微信聊天记录:WeChatMsg完整操作指南
  • AI优化建议:让AI帮你优化代码性能
  • 别再手动转IMU了!用MATLAB实现椭球拟合自动校准加速度计(附完整代码)
  • 从MLM到RTD:一文读懂DeBERTa V3的预训练任务革新与HuggingFace快速上手
  • 鸿蒙刘海屏、水滴屏、瀑布屏适配:用 DisplayUtil 获取不可用区域
  • 从PC到AI,联想中国一场必打的仗
  • 如何快速上手AdelaiDepth:5分钟实现单目深度估计 [特殊字符]
  • HarmonyOS FoldStatus 与 FoldDisplayMode 枚举深度解析:折叠屏开发不再难
  • 多家对比才知道!机闸一体式钢制闸门哪家好、哪家优惠?认准河北闸之都实体厂家,可定制,品质价格双保障 - 栗子测评
  • 10个免费VMware Workstation Pro 17许可证密钥:专业虚拟化快速激活指南
  • LightRAG 入门指南:手把手教你用图增强 RAG 系统
  • 别再死记硬背了!用COMSOL做场路耦合,搞懂‘外部U vs. I’和‘外部I vs. U’到底怎么选
  • 2026年移动岗亭十大品牌厂家推荐:不锈钢/铝合金/雕花板岗亭,小区/工地/景区/警务/收费多场景定制选购指南 - 品牌企业推荐师(官方)
  • 从理论到实践:MiniCPM5-1B-MLX架构设计与实现原理深度剖析
  • 智能体时代,AI支付会是下一个“二维码”吗?
  • Bat批处理进阶玩法:用ren命令批量重命名,实现‘去头掐尾’和‘中间替换’
  • 2026年 EPS/EPP源头厂家最新推荐榜:东莞EPS颗粒、阻燃EPS板材、EPP保温箱及EPP托盘与周转箱专业实力深度解析 - 品牌企业推荐师(官方)
  • R语言偏相关分析实战:用ppcor包和自定义函数搞定土壤微生物数据