【HarmonyOS】应用振动效果实现(Vibrator)

【HarmonyOS】应用振动效果实现(Vibrator)
基于 HarmonyOS 5 / API 12ArkTS 最新写法适用于 HarmonyOS NEXT第一章 Vibrator介绍移动应用中振动Haptic Feedback已经成为交互设计中不可缺少的一部分。例如点击按钮长按菜单删除确认支付成功消息提醒游戏反馈指纹识别NFC识别相机拍照都会通过振动给予用户即时反馈。HarmonyOS 提供了Vibrator振动器模块开发者可以直接控制设备马达实现丰富的触觉体验。官方提供了启动振动、停止振动、查询振动能力等接口。第二章 Vibrator工作原理整个振动系统主要分为四层ArkTS Application │ ▼ SensorServiceKit │ ▼ Vibrator Framework │ ▼ Vibrator Service │ ▼ Hardware Driver(HDF) │ ▼ Linear Motor开发者调用startVibration()实际上会经过ArkTS ↓ Framework ↓ Service ↓ 驱动 ↓ 手机马达整个过程全部由系统完成。第三章 权限配置振动属于系统能力。因此需要申请权限ohos.permission.VIBRATEmodule.json5{ module: { requestPermissions: [ { name: ohos.permission.VIBRATE } ] } }否则调用 Vibrator 接口无法正常触发振动。第四章 导入模块HarmonyOS 5 推荐使用import { vibrator } from kit.SensorServiceKit之后即可调用全部 Vibrator API。第五章 最简单的振动最常见的是固定时间振动。例如import { vibrator } from kit.SensorServiceKit vibrator.startVibration( { type: time, duration: 100 }, { id: 0, usage: alarm })运行后手机振动100ms这就是最简单的振动。第六章 Promise写法推荐使用 async。async function vibrate(){ try{ await vibrator.startVibration( { type:time, duration:150 }, { id:0, usage:alarm }) }catch(err){ console.error(err) } }企业开发全部推荐 Promise。第七章 Callback写法当然官方仍支持 Callback。vibrator.startVibration( { type:time, duration:80 }, { id:0, usage:alarm }, (){ console.info(振动完成) })现在基本已经很少使用。第八章 振动时间控制例如30ms轻触50ms普通点击100ms按钮点击200ms长按反馈500ms消息提醒1000ms报警通常建议普通UI30~80ms不要超过100ms否则体验较差。第九章 VibrateAttribute详解第二个参数就是VibrateAttribute例如{ id:0, usage:alarm }usage代表此次振动属于什么业务。例如alarm闹钟notification通知ringtone来电media媒体系统会根据不同业务调整振动策略。第十章 预设振动效果Preset Effect除了按照时间进行振动外HarmonyOS 还提供了系统内置的预设振动效果Preset Effect。相比固定时间振动预设振动具有以下优势更符合 HarmonyOS 系统交互规范系统会根据设备马达自动调整力度不同型号设备体验更加统一功耗更低触觉反馈更加自然例如按钮点击 ↓ 系统短促振动 长按 ↓ 系统长反馈 确认操作 ↓ Success Haptic 错误提示 ↓ Warning Haptic实际开发中如果系统已经提供对应效果优先使用预设振动而不是自己设置 duration。第十一章 查询系统支持的振动效果不同手机硬件不同。并不是所有振动效果都支持。HarmonyOS 提供接口用于查询。示例import { vibrator } from kit.SensorServiceKit async function checkSupport() { try { let supported await vibrator.isSupportEffect(haptic.clock.timer) console.info(是否支持${supported}) } catch (err) { console.error(JSON.stringify(err)) } }输出是否支持true如果返回false说明当前设备没有对应马达效果。开发中建议先判断 ↓ 支持 ↓ 播放 ↓ 否则 ↓ 降级普通振动这样兼容性最好。第十二章 查询设备支持哪些振动效果有时候并不知道设备支持哪些效果。可以获取支持列表。例如async function queryEffects() { try { const list await vibrator.getSupportedEffects() console.info(JSON.stringify(list)) } catch (err) { console.error(JSON.stringify(err)) } }可能输出[ haptic.clock.timer, haptic.camera.click, haptic.common.long_press, haptic.notification ]开发大型应用时可以启动时缓存App启动 ↓ 读取支持列表 ↓ 保存到内存 ↓ 后续直接判断避免重复查询提高性能。第十三章 停止振动如果振动时间比较长。例如3000ms用户提前退出页面。需要主动停止。HarmonyOS 提供await vibrator.stopVibration()完整示例import { vibrator } from kit.SensorServiceKit async function stop() { try { await vibrator.stopVibration() } catch (err) { console.error(err) } }适用场景页面关闭Dialog 消失Activity 生命周期结束视频播放停止游戏退出第十四章 自定义连续振动很多业务不是一次振动。例如滴 停一下 滴滴 停一下 滴这种就是连续振动。可以利用异步实现import { vibrator } from kit.SensorServiceKit async function play() { for(let i0;i3;i){ await vibrator.startVibration( { type:time, duration:100 },{ id:0, usage:notification }) await new Promise(resolve{ setTimeout(resolve,200) }) } }效果振100ms ↓ 停200ms ↓ 振100ms ↓ 停200ms ↓ 振100ms这种方式适合SOS消息提醒游戏技能支付等待第十五章 不同业务推荐振动时长很多开发者喜欢duration1000这是错误的。推荐值如下场景推荐时间Button30~50msCard Click30msTab切换20msSwitch20ms长按80ms删除100ms支付成功120ms支付失败150ms消息提醒150ms来电系统控制闹钟系统控制经验UI 操作越轻振动越短。第十六章 Button点击反馈例如Button(登录) .onClick(async (){ await vibrator.startVibration( { type:time, duration:40 },{ id:0, usage:touch }) })用户点击按钮。立即得到触觉反馈。体验明显提升。第十七章 List点击反馈例如商品列表商品A 商品B 商品C点击ListItem() .onClick(async (){ await vibrator.startVibration( { type:time, duration:25 },{ id:0, usage:touch }) })比普通点击更有质感。第十八章 长按反馈长按一般需要80ms示例Gesture( LongPressGesture() .onAction(async (){ await vibrator.startVibration( { type:time, duration:80 },{ id:0, usage:touch }) }))用户会明显感觉已经进入长按模式第十九章 删除确认振动例如删除成功可以给予一次明显反馈。await vibrator.startVibration( { type:time, duration:120 },{ id:0, usage:notification })删除失败150ms ↓ 两次连续振动更容易区分。第二十章 支付成功反馈支付完成支付成功 ↓ √ ↓ 轻微振动 ↓ 动画示例await vibrator.startVibration( { type:time, duration:80 },{ id:0, usage:notification })再播放Success Animation体验接近系统应用。第二十一章 登录失败反馈登录失败推荐振动 ↓ Toast ↓ 输入框Shake动画代码await vibrator.startVibration( { type:time, duration:120 },{ id:0, usage:notification })用户无需阅读文字。就知道登录失败第二十二章 页面返回反馈例如返回上一页可以20ms轻触。示例.onClick(async (){ await vibrator.startVibration( { type:time, duration:20 },{ id:0, usage:touch }) router.back() })几乎所有系统应用都有类似反馈。第二十三章 页面切换反馈例如首页 ↓ 分类 ↓ 购物车 ↓ 我的BottomNavigation点击 ↓ 20ms振动 ↓ 动画用户感知明显。建议不要超过30ms否则切换会感觉拖沓。第二十四章 企业级 VibratorManager 封装很多项目都是这样写Button(登录) .onClick(async (){ await vibrator.startVibration(...) }) Button(删除) .onClick(async (){ await vibrator.startVibration(...) }) Button(收藏) .onClick(async (){ await vibrator.startVibration(...) })项目越来越大之后会出现很多问题到处都是重复代码duration 不统一usage 不统一修改体验需要全局搜索无法统一关闭振动因此企业项目都会封装UI ↓ VibratorManager ↓ SensorServiceKit ↓ Hardware这样整个项目只有一个入口。第二十五章 封装 VibratorManager创建utils/ VibratorManager.ets代码如下import { vibrator } from kit.SensorServiceKit export class VibratorManager { /** * 普通点击 */ static async click() { try { await vibrator.startVibration( { type:time, duration:30 }, { id:0, usage:touch }) } catch {} } /** * 长按 */ static async longPress() { try { await vibrator.startVibration( { type:time, duration:80 }, { id:0, usage:touch }) } catch {} } /** * 成功 */ static async success() { try { await vibrator.startVibration( { type:time, duration:100 }, { id:0, usage:notification }) } catch {} } }以后调用await VibratorManager.click()即可。是不是干净很多第二十六章 页面使用例如Button(登录) .onClick((){ VibratorManager.click() })删除Button(删除) .onClick((){ VibratorManager.success() })整个项目代码统一。第二十七章 枚举统一管理很多人喜欢这样30 50 80 100 120到处都是魔法数字。建议export enum VibrateTime{ CLICK30, TAB20, LONG_PRESS80, SUCCESS100, ERROR150 }以后duration:VibrateTime.SUCCESS可读性立即提升。第二十八章 高频点击问题例如Button ↓↓↓↓↓↓↓↓↓↓↓ 疯狂点击结果振 振 振 振 振 振 振用户会觉得手机坏了所以企业项目必须做防抖Debounce第二十九章 防抖实现例如private static lastTime:number0 static async click(){ let nowDate.now() if(now-this.lastTime100){ return } this.lastTimenow await vibrator.startVibration(...) }这样100ms以内 ↓ 忽略避免连续振动。第三十章 节流实现如果List ↓ 快速滑动 ↓ 一直点击可以300ms ↓ 允许一次实现private static interval300体验更舒服。第三十一章 全局开关很多用户设置 ↓ 关闭触觉反馈所以class VibratorManager{ static enabletrue }调用if(!this.enable){ return }以后设置 ↓ 关闭振动 ↓ 整个APP立即生效第三十二章 与设置页面联动例如设置 ☑ 开启声音 ☑ 开启振动代码Preference.putBoolean( haptic_enable, true )读取Preference.getBoolean( haptic_enable, true )初始化VibratorManager.enablevalue即可。第三十三章 登录页面最佳实践用户点击登录推荐点击 ↓ 30ms振动 ↓ Loading ↓ 成功 ↓ 100ms振动 ↓ 进入首页失败点击 ↓ 30ms ↓ 请求失败 ↓ 150ms ↓ Shake动画 ↓ Toast体验明显更好。第三十四章 商城App最佳实践商品加入购物车推荐点击 ↓ 30ms ↓ 商品飞入购物车 ↓ 角标动画收藏❤ ↓ 30ms ↓ 缩放动画删除删除商品 ↓ 100ms ↓ Snackbar支付成功 ↓ 120ms ↓ Success动画第三十五章 聊天App实践发送发送消息建议20ms收到消息系统通知 ↓ Notification vibration撤回40ms长按80ms第三十六章 游戏最佳实践例如攻击20ms暴击80msBoss死亡100ms ↓ 停100ms ↓ 100ms升级Success vibration不要连续5秒用户会直接关闭振动。第三十七章 与动画联动最好的体验不是振动 结束 动画而是振动 动画 声音例如按钮点击 ↓ Scale ↓ Vibrate ↓ ClickSound整个反馈视觉 触觉 听觉体验提升非常明显。第三十八章 与 Lottie 联动例如支付成功√ ↓ Lottie动画 ↓ Success Vibrate ↓ Success Sound这就是大型 App 常见的多模态反馈设计。第三十九章 生命周期管理页面退出aboutToDisappear(){ vibrator.stopVibration() }避免页面退出 ↓ 手机还在震尤其长时间振动循环振动自定义节奏振动都应该停止。第四十章 多页面统一管理建议Application ↓ AppManager ↓ VibratorManager ↓ 所有Page不要每个页面 ↓ 自己调用API否则以后修改duration usage 节流 日志 权限需要改几十个地方。第四十一章 日志封装企业项目一般会统一记录Logger.info( Click Vibrate )例如Logger.info( Success Vibrate )方便排查为什么没振动 ↓ 是否调用 ↓ 是否异常 ↓ 是否权限 ↓ 是否硬件第四十二章 异常处理千万不要await vibrator.startVibration(...)什么都不处理。正确try{ await vibrator.startVibration(...) }catch(err){ console.error(JSON.stringify(err)) }这样权限问题API 调用失败设备不支持系统限制都可以及时发现。第四十三章 功耗优化虽然振动时间通常很短但如果100ms × 1000 次不仅影响体验还会增加耗电。建议点击反馈20~40ms长按反馈60~80ms成功反馈80~120ms错误反馈120~150ms不要在滑动过程中持续振动不要在动画每一帧都触发振动高频事件必须增加防抖或节流第四十四章 企业级目录结构推荐将振动模块独立管理common/ ├── manager/ │ └── VibratorManager.ets ├── constant/ │ └── VibrateTime.ets ├── model/ │ └── VibrateType.ets ├── utils/ │ └── HapticUtils.ets └── preference/ └── SettingPreference.ets这种结构适合中大型项目后续扩展预设振动、用户配置、日志统计等功能都比较方便。第四十五章 Vibrator API 全解析HarmonyOS 振动能力主要由kit.SensorServiceKit提供。导入import { vibrator } from kit.SensorServiceKit开发过程中常用的 API 主要有以下几个API作用推荐指数startVibration()开始振动★★★★★stopVibration()停止振动★★★★★isSupportEffect()判断是否支持指定振动效果★★★★☆getSupportedEffects()获取设备支持的效果列表★★★★☆其中startVibration()是最核心的接口。第四十六章 startVibration() 参数详解典型调用方式await vibrator.startVibration( { type: time, duration: 60 }, { id: 0, usage: touch } )第一个参数表示振动配置。参数类型说明typestring振动类型durationnumber振动时长毫秒目前最常用的是type: time表示按照时间振动。第二个参数{ id:0, usage:touch }属于 VibrateAttribute。常见 usageusage场景touch点击反馈notification通知alarm闹钟ringtone来电media多媒体建议普通按钮touch支付成功notification闹钟alarm不要全部都使用alarm否则系统无法进行最佳调度。第四十七章 Promise 与 async 推荐写法推荐async function click(){ try{ await vibrator.startVibration( { type:time, duration:30 },{ id:0, usage:touch }) }catch(err){ console.error(err) } }不要vibrator.startVibration(...) vibrator.startVibration(...) vibrator.startVibration(...)没有等待结束。容易出现多个请求重叠。第四十八章 常见异常企业开发中最容易遇到的问题主要有以下几种。问题一没有振动原因没有申请权限解决module.json5 ↓ 添加 ohos.permission.VIBRATE问题二真机没有反应可能原因手机关闭了触觉反馈建议应用增加设置 ↓ 开启振动让用户自行控制。问题三模拟器无法测试HarmonyOS 模拟器没有真实线性马达所以不会振动必须使用真机开发。问题四设备不支持指定效果例如isSupportEffect(...)返回false说明硬件不支持建议自动降级Preset Effect ↓ 失败 ↓ 普通Time Vibrate问题五连续调用失败例如for(){ startVibration() }疯狂执行。系统可能忽略 或者 合并所以建议增加100ms以上间隔第四十九章 企业级降级方案很多手机支持 Success Click LongPress但是Error Warning 没有企业项目一般这样设计播放预设 ↓ 失败 ↓ 播放普通振动 ↓ 失败 ↓ 忽略代码思想try{ 播放Preset }catch{ try{ 普通振动 }catch{ } }兼容性最好。第五十章 HapticFeedbackManager 完整设计推荐采用单例模式。整体结构HapticFeedbackManager ├── click() ├── success() ├── warning() ├── error() ├── longPress() ├── stop() ├── enable() ├── disable() ├── checkSupport() └── play()以后整个 APP全部调用HapticFeedbackManager.click()而不是vibrator.startVibration(...)第五十一章 推荐的振动规范建议统一设计规范。操作推荐Button30msCard30msTab20msDialog确认40ms长按80ms删除成功100ms支付成功100~120ms登录失败150ms错误提示两段振动整个项目保持一致。用户体验会统一很多。第五十二章 企业项目最佳实践建议一、不要所有点击都振动例如List ↓ 滑动 ↓ 每一个Item ↓ 全部振动用户很快烦躁建议重要操作才振动。二、振动不要替代动画应该动画 振动 声音而不是只有振动三、尊重系统设置如果用户关闭 触觉反馈建议应用同步关闭。不要强制振动。四、不要长时间振动很多开发者2000ms实际上体验非常差。建议绝大部分30~120ms已经足够。五、不要连续疯狂调用例如Scroll ↓ 每一帧 ↓ 振动这是最严重的问题之一。第五十三章 完整流程图用户点击 │ ▼ UI组件(Button) │ ▼ VibratorManager.click() │ ▼ 判断是否开启 │ ▼ 判断设备支持 │ ▼ 播放Preset │ 失败 │ 是──────────────┐ │ │ ▼ │ 普通Time Vibrate │ │ │ ▼ │ try catch────────┘ │ ▼ 返回UI这是企业项目比较成熟的一套流程。第五十四章 完整项目目录建议entry │ ├── pages │ ├── common │ │ ├── manager │ │ VibratorManager.ets │ │ │ ├── constant │ │ VibrateConstant.ets │ │ │ ├── model │ │ VibrateModel.ets │ │ │ ├── utils │ │ VibrateUtils.ets │ │ │ └── preference │ SettingPreference.ets │ └── resources大型项目建议统一管理不要在各个页面直接调用底层 API。第五十五章 性能优化建议企业级应用中可以遵循以下原则建议原因使用单例管理振动避免重复创建对象增加防抖防止高频触发页面销毁时停止振动防止资源泄漏查询支持能力后缓存减少重复调用使用系统预设效果更统一、更节能提供用户开关尊重用户体验