手把手封装鸿蒙震动工具类,覆盖全场景触觉反馈需求
摘要:本文介绍了华为HarmonyOS中的震动API技术,包括时长震动、预设效果和自定义模式三种震动类型及其核心API用法。针对实际开发需求,文章提出了一套增强版震动工具类设计方案,强调标准化封装、类型安全、异常防护和设备兼容性适配。该工具类通过枚举定义震动效果和用途,提供异步化操作接口,并内置设备兼容性检测,可广泛应用于按钮点击、操作反馈等场景,为鸿蒙应用开发提供即插即用的震动解决方案。
鸿蒙震动技术实战
概述
在移动应用开发中,触觉反馈是提升用户体验的重要组成部分。适当的震动反馈可以增强用户与应用的交互感,提供操作确认,减轻视觉依赖,甚至可以传递情感信息。华为 HarmonyOS 提供了丰富的震动 API,使开发者能够为应用添加多样化的触觉反馈效果。
本文将详细介绍 HarmonyOS 中的震动 API,结合 CatIsland 项目的实际应用,展示如何在应用中实现各种震动效果,并提供一个可直接使用的震动工具类。
震动 API 介绍
核心模块
HarmonyOS 提供了 @kit.SensorServiceKit 模块用于控制设备震动,主要使用其中的 vibrator 相关 API。
震动类型
HarmonyOS 支持三种类型的震动:
- 时长震动:指定震动持续时间
- 预设效果:使用系统预设的震动模式
- 自定义模式:通过震动模式数组实现复杂效果
核心 API
1. 时长震动
import { vibrator } from "@kit.SensorServiceKit";
import { BusinessError } from "@kit.BasicServicesKit";
// 启动指定时长的震动
vibrator.startVibration({
type: 'time',
duration: 100 // 震动持续时间,单位毫秒
}, {
usage: 'physicalFeedback' // 震动用途
}, (error: BusinessError<void>) => {
if (error) {
console.error(`启动震动失败: ${error.code}, ${error.message}`);
return;
}
console.info('震动启动成功');
});
2. 预设效果震动
// 启动预设效果的震动
vibrator.startVibration({
type: 'preset',
effectId: 'haptic.effect.soft', // 预设效果ID
count: 1 // 震动次数
}, {
usage: 'physicalFeedback'
}, (error: BusinessError<void>) => {
if (error) {
console.error(`启动震动失败: ${error.code}, ${error.message}`);
return;
}
console.info('震动启动成功');
});
3. 自定义模式震动
// 启动自定义模式的震动
vibrator.startVibration({
type: 'pattern',
pattern: [100, 200, 100, 300], // 震动模式数组,交替表示震动和暂停的时长
repeat: -1 // 重复次数,-1表示无限循环
}, {
usage: 'physicalFeedback'
}, (error: BusinessError<void>) => {
if (error) {
console.error(`启动震动失败: ${error.code}, ${error.message}`);
return;
}
console.info('震动启动成功');
});
4. 停止震动
// 停止震动
vibrator.stopVibration('all', (error: BusinessError<void>) => {
if (error) {
console.error(`停止震动失败: ${error.code}, ${error.message}`);
return;
}
console.info('震动停止成功');
});
5. 检查效果是否支持
// 检查预设效果是否支持
vibrator.isSupportEffect('haptic.effect.soft', (err: BusinessError<void>, state: boolean) => {
if (err) {
console.error(`检查效果失败: ${err.code}, ${err.message}`);
return;
}
console.info(`效果是否支持: ${state}`);
if (state) {
// 效果支持,可以使用
}
});
最佳实践
在实际项目开发中,震动反馈的合理落地不仅需要掌握基础API用法,更要兼顾可维护性、兼容性与用户体验。直接零散调用vibrator API会导致代码冗余、异常处理混乱、设备适配不足等问题,因此封装一套标准化、可复用的震动工具类,是鸿蒙震动技术落地的最优路径。
结合喵屿项目的实战经验,我们围绕"易用性、健壮性、可扩展性"三大核心,设计并实现了一套增强版震动工具类,覆盖开发中常见的震动场景,同时规避各类潜在问题,可直接集成到任意鸿蒙应用中使用。
工具类设计思路
针对项目开发中震动反馈的痛点,工具类设计遵循以下核心思路,确保落地高效、体验优质:
-
标准化封装:将震动相关的所有操作(启动、停止、兼容性检测)统一封装,避免代码重复编写,降低维护成本,同时统一交互体验。
-
类型安全约束:通过枚举定义震动效果、震动用途,避免开发者因传入错误参数导致功能异常,同时提供清晰的类型提示,提升开发效率。
-
异步化适配:采用Promise封装所有异步操作,替代传统回调函数,解决回调嵌套问题,更符合现代前端开发习惯,便于结合业务逻辑串联执行。
-
全链路异常防护:对所有API调用添加异常捕获,避免因设备不支持、权限缺失等问题导致应用崩溃,同时输出清晰的错误日志,便于问题排查。
-
设备兼容性适配:内置设备震动支持性、预设效果支持性检测,自动跳过不支持的操作,确保在不同鸿蒙设备上均能稳定运行,无需额外开发适配逻辑。
-
场景化快捷适配:针对按钮点击、长按、操作成功/失败、通知提醒等高频场景,提供一键调用的快捷方法,简化开发流程,无需重复配置参数。
增强版震动工具类(可直接复制复用)
基于上述设计思路,我们实现了功能全面、健壮性强的震动工具类,涵盖所有主流震动场景,同时优化了代码冗余,提升了可扩展性,具体实现如下:
import { vibrator } from "@kit.SensorServiceKit";
import { BusinessError } from "@kit.BasicServicesKit";
/**
* 预设震动效果枚举(统一管理系统预设效果,避免硬编码)
* 涵盖基础震动、通知类、交互类三大场景,适配绝大多数应用需求
*/
export enum VibrateEffect {
// 基础震动效果(适用于简单反馈)
SOFT = 'haptic.effect.soft', // 轻微震动(低强度,不突兀)
HARD = 'haptic.effect.hard', // 强烈震动(高强度,用于重要反馈)
SHARP = 'haptic.effect.sharp', // 尖锐震动(短促有力,用于精准交互)
// 通知类震动效果(适用于操作结果反馈)
NOTICE_SUCCESS = 'haptic.notice.success', // 成功通知(柔和,传递正向反馈)
NOTICE_WARNING = 'haptic.notice.warning', // 警告通知(中等强度,提醒注意)
NOTICE_FAIL = 'haptic.notice.fail', // 失败通知(急促,传递异常反馈)
// 交互类震动效果(适用于用户主动操作)
INTERACTION_CLICK = 'haptic.interaction.click', // 点击震动(短促,确认操作)
INTERACTION_LONG_PRESS = 'haptic.interaction.longPress', // 长按震动(稍长,区分点击与长按)
}
/**
* 震动用途枚举(明确震动场景,适配系统权限与资源分配)
*/
export enum VibrateUsage {
PHYSICAL_FEEDBACK = 'physicalFeedback', // 物理反馈(默认,适用于交互操作)
ALARM = 'alarm', // 闹钟震动(高强度,用于唤醒)
RINGTONE = 'ringtone', // 铃声震动(与铃声同步,提升提醒效果)
NOTIFICATION = 'notification', // 通知震动(中等强度,不打扰用户)
}
/**
* 增强型震动工具类(全局复用,统一管理震动逻辑)
* 提供完整的震动控制、兼容性检测、快捷调用能力,适配鸿蒙全机型
*/
export class VibrateUtil {
/**
* 检查当前设备是否支持震动功能
* @returns Promise<boolean> 设备是否支持震动(true:支持,false:不支持)
*/
public static async isVibratorSupported(): Promise<boolean> {
return new Promise((resolve) => {
try {
// 以常用的轻微震动效果为检测基准,判断设备是否具备震动能力
vibrator.isSupportEffect(VibrateEffect.SOFT, (err: BusinessError<void>, state: boolean) => {
if (err) {
console.error(`设备震动支持性检测失败:${err.code} - ${err.message}`);
resolve(false);
return;
}
resolve(state);
});
} catch (error) {
console.error(`设备震动检测异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
/**
* 检查指定预设震动效果是否被当前设备支持
* @param effect 震动效果(从VibrateEffect枚举中取值)
* @returns Promise<boolean> 该效果是否支持(true:支持,false:不支持)
*/
public static async isEffectSupported(effect: VibrateEffect): Promise<boolean> {
return new Promise((resolve) => {
try {
vibrator.isSupportEffect(effect, (err: BusinessError<void>, state: boolean) => {
if (err) {
console.error(`震动效果${effect}检测失败:${err.code} - ${err.message}`);
resolve(false);
return;
}
resolve(state);
});
} catch (error) {
console.error(`震动效果${effect}检测异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
/**
* 时长震动(自定义震动持续时间,适用于基础反馈场景)
* @param duration 震动持续时间(单位:毫秒,建议10-500ms)
* @param usage 震动用途(默认:物理反馈,根据场景灵活选择)
* @returns Promise<boolean> 震动操作是否执行成功(true:成功,false:失败)
*/
public static async vibrateByDuration(
duration: number,
usage: VibrateUsage = VibrateUsage.PHYSICAL_FEEDBACK
): Promise<boolean> {
// 校验时长合理性,避免无效震动(过短无感知,过长影响体验)
if (duration < 10 || duration > 500) {
console.warn(`震动时长${duration}ms不合理,建议设置10-500ms`);
return false;
}
return new Promise((resolve) => {
try {
vibrator.startVibration(
{ type: 'time', duration: duration },
{ usage: usage },
(error: BusinessError<void>) => {
if (error) {
console.error(`时长震动启动失败:${error.code} - ${error.message}`);
resolve(false);
return;
}
console.info(`时长${duration}ms震动启动成功`);
resolve(true);
}
);
} catch (error) {
console.error(`时长震动执行异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
/**
* 预设效果震动(使用系统预设效果,统一交互体验,推荐优先使用)
* @param effect 震动效果(从VibrateEffect枚举中取值)
* @param count 震动次数(默认1次,多次震动适用于强提醒场景)
* @param usage 震动用途(默认:物理反馈)
* @returns Promise<boolean> 震动操作是否执行成功(true:成功,false:失败)
*/
public static async vibrateByEffect(
effect: VibrateEffect,
count: number = 1,
usage: VibrateUsage = VibrateUsage.PHYSICAL_FEEDBACK
): Promise<boolean> {
// 先检测当前设备是否支持该预设效果,避免无效调用
const isSupported = await this.isEffectSupported(effect);
if (!isSupported) {
console.warn(`当前设备不支持${effect}震动效果,已跳过执行`);
return false;
}
// 校验震动次数合理性
if (count < 1 || count > 5) {
console.warn(`震动次数${count}不合理,建议设置1-5次`);
return false;
}
return new Promise((resolve) => {
try {
vibrator.startVibration(
{ type: 'preset', effectId: effect, count: count },
{ usage: usage },
(error: BusinessError<void>) => {
if (error) {
console.error(`预设效果${effect}震动启动失败:${error.code} - ${error.message}`);
resolve(false);
return;
}
console.info(`预设效果${effect}震动启动成功,共${count}次`);
resolve(true);
}
);
} catch (error) {
console.error(`预设效果${effect}震动执行异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
/**
* 自定义模式震动(灵活配置震动/暂停节奏,适用于复杂反馈场景)
* @param pattern 震动模式数组(交替表示震动、暂停的时长,单位:毫秒)
* @param repeat 重复次数(-1表示无限循环,0表示不重复,建议不超过5次)
* @param usage 震动用途(默认:物理反馈)
* @returns Promise<boolean> 震动操作是否执行成功(true:成功,false:失败)
*/
public static async vibrateByPattern(
pattern: number[],
repeat: number = -1,
usage: VibrateUsage = VibrateUsage.PHYSICAL_FEEDBACK
): Promise<boolean> {
// 校验模式数组合理性(长度至少2,确保有震动有暂停)
if (!pattern || pattern.length < 2) {
console.warn(`自定义震动模式数组无效,需至少包含2个元素(震动+暂停)`);
return false;
}
// 校验重复次数合理性
if (repeat < -1 || repeat > 5) {
console.warn(`重复次数${repeat}不合理,建议设置-1(无限循环)或0-5次`);
return false;
}
return new Promise((resolve) => {
try {
vibrator.startVibration(
{ type: 'pattern', pattern: pattern, repeat: repeat },
{ usage: usage },
(error: BusinessError<void>) => {
if (error) {
console.error(`自定义模式震动启动失败:${error.code} - ${error.message}`);
resolve(false);
return;
}
console.info(`自定义模式震动启动成功,重复次数:${repeat === -1 ? '无限' : repeat}次`);
resolve(true);
}
);
} catch (error) {
console.error(`自定义模式震动执行异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
/**
* 停止震动(按需停止指定类型或所有震动,避免无效震动消耗电量)
* @param stopMode 停止模式(all:停止所有;time:停止时长震动;preset:停止预设效果震动;pattern:停止自定义模式震动)
* @returns Promise<boolean> 停止操作是否执行成功(true:成功,false:失败)
*/
public static async stopVibration(
stopMode: 'all' | 'time' | 'preset' | 'pattern' = 'all'
): Promise<boolean> {
return new Promise((resolve) => {
try {
vibrator.stopVibration(stopMode, (error: BusinessError<void>) => {
if (error) {
console.error(`停止${stopMode}类型震动失败:${error.code} - ${error.message}`);
resolve(false);
return;
}
console.info(`${stopMode}类型震动已成功停止`);
resolve(true);
});
} catch (error) {
console.error(`停止${stopMode}类型震动异常:${(error as BusinessError).code} - ${(error as BusinessError).message}`);
resolve(false);
}
});
}
// ———— 高频场景快捷方法(简化开发,一键调用,无需重复配置) ————
/**
* 按钮点击震动(快捷调用,适用于所有按钮点击交互)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async buttonClick(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.INTERACTION_CLICK);
}
/**
* 按钮长按震动(快捷调用,区分点击与长按操作,提升交互辨识度)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async buttonLongPress(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.INTERACTION_LONG_PRESS);
}
/**
* 操作成功反馈震动(快捷调用,适用于表单提交、任务完成等场景)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async successFeedback(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.NOTICE_SUCCESS, 1, VibrateUsage.NOTIFICATION);
}
/**
* 操作警告反馈震动(快捷调用,适用于参数错误、操作提醒等场景)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async warningFeedback(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.NOTICE_WARNING, 1, VibrateUsage.NOTIFICATION);
}
/**
* 操作失败反馈震动(快捷调用,适用于提交失败、接口异常等场景)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async failFeedback(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.NOTICE_FAIL, 1, VibrateUsage.NOTIFICATION);
}
/**
* 轻微震动(快捷调用,适用于次要交互、弱反馈场景)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async softVibrate(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.SOFT);
}
/**
* 强烈震动(快捷调用,适用于重要提醒、强反馈场景)
* @returns Promise<boolean> 震动操作是否执行成功
*/
public static async hardVibrate(): Promise<boolean> {
return this.vibrateByEffect(VibrateEffect.HARD);
}
}
工具类实战使用示例
结合喵屿项目的实际交互场景,以下示例展示了工具类在不同业务场景中的使用方式,简洁高效,可直接复制到项目中适配自身业务:
示例1:按钮点击交互(最常用场景)
适用于应用内所有按钮点击反馈,通过短促震动确认用户操作,提升交互质感:
// 导入工具类(根据项目路径调整导入路径)
import { VibrateUtil } from '../utils/VibrateUtil';
// 按钮组件使用
Button('保存')
.width(120)
.height(40)
.onClick(async () => {
// 先触发点击震动,再执行业务逻辑
await VibrateUtil.buttonClick();
// 执行相关业务操作
console.log('保存数据');
});

示例2:操作结果反馈(成功/失败场景)
适用于表单提交、数据保存、接口请求等场景,通过不同震动效果传递操作结果,减少视觉依赖:
// 模拟表单提交业务
async function submitPetInfo(petInfo: object) {
try {
// 模拟接口请求
const response = await fetch('/api/pet/info', {
method: 'POST',
body: JSON.stringify(petInfo)
});
if (response.ok) {
// 提交成功,触发成功震动反馈
await VibrateUtil.successFeedback();
console.log('宠物信息提交成功');
} else {
// 提交失败,触发失败震动反馈
await VibrateUtil.failFeedback();
console.log('宠物信息提交失败');
}
} catch (error) {
// 异常情况,触发失败震动反馈
await VibrateUtil.failFeedback();
console.error('宠物信息提交异常:', error);
}
}
示例3:自定义节奏震动(特殊场景)
适用于特殊提醒场景(如猫咪状态提醒、定时喂养提醒),通过自定义震动节奏实现差异化反馈:
// 模拟猫咪饥饿提醒震动(心跳式节奏)
async function petHungryRemind() {
// 震动模式:震动100ms → 暂停100ms → 震动100ms → 暂停800ms,重复3次
const pattern = [100, 100, 100, 800];
await VibrateUtil.vibrateByPattern(pattern, 3);
console.log('猫咪饥饿提醒震动触发');
}
// 调用提醒方法
petHungryRemind();
示例4:手动停止震动(特殊需求场景)
适用于无限循环震动场景(如紧急提醒),允许用户手动停止震动,提升用户体验:
// 启动无限循环震动(紧急提醒)
async function startEmergencyRemind() {
const pattern = [200, 300]; // 震动200ms,暂停300ms,无限循环
await VibrateUtil.vibrateByPattern(pattern, -1);
}
// 停止所有震动(用户手动触发)
Button('停止提醒')
.onClick(async () => {
await VibrateUtil.stopVibration('all');
console.log('所有震动已停止');
});
注意事项
- 权限配置:在
module.json5文件中配置震动权限
"requestPermissions": [
{
"name": "ohos.permission.VIBRATE"
}
]
-
设备兼容性:不同设备的震动效果可能有所差异,建议在多种设备上测试
-
用户设置:尊重用户的系统震动设置,避免在用户关闭震动时强制触发震动
-
适度使用:震动反馈应适度使用,过度使用可能会引起用户不适
-
错误处理:始终添加错误处理,确保震动操作不会影响应用的正常运行
总结
震动反馈是提升应用用户体验的重要手段,通过合理使用 HarmonyOS 提供的震动 API,可以为用户提供更加丰富、直观的交互体验。本文详细介绍了 HarmonyOS 中的震动 API,包括核心模块、震动类型和核心 API 的使用方法,并提供了一个功能全面、设计合理的震动工具类。
通过本文的介绍,相信开发者们已经对鸿蒙震动技术有了全面的了解,并能够在自己的项目中实现各种震动效果,为用户提供更加优质的触觉交互体验。
更多推荐



所有评论(0)