【HarmonyOS】应用振动效果实现

一、问题背景:

应用在强提醒场景下,一般会有马达振动的效果,提示用户注意力的关注。

比如消息提醒,扫码提示,删除键确认提示等。

针对高定制化或者固定的振动方式,我们需要有不同的方案实现,马达振动效果。

二、解决方案:

鸿蒙针对振动效果的实现,有多种方案,目前分为振动和音振协同两种方式。

单纯的只是振动,又分为三种方式:

  1. 系统定制的振动方式,例如闹钟
  2. 非系统定制,自定义振动配置json文件的方式
  3. 线性马达振动,只需要设置时间和强度(最简单的调用方式)

音振协同一般用于,音效播放和振动同时的场景,例如扫码。

1.首先需要配置振动权限,该权限是系统权限,只需要配置后,默认就会被授权。

ohos.permission.VIBRATE

2.之后根据需要实现不同的马达振动效果,方案调用详情参见下方代码示例的注释。

三、DEMO示例:

dart 复制代码
import vibrator from '@ohos.vibrator';
import { BusinessError } from '@ohos.base';
import { resourceManager } from '@kit.LocalizationKit';

/**
 * 振动管理类
 * 需要权限: ohos.permission.VIBRATE
 */
export class HapticMgr {
  private TAG: string = 'HapticMgr';

  private static mHapticMgr: HapticMgr | undefined = undefined;

  public static Ins(): HapticMgr{
    if(!HapticMgr.mHapticMgr){
      HapticMgr.mHapticMgr = new HapticMgr();
    }
    return HapticMgr.mHapticMgr;
  }

  /**
   * 按照指定持续时间触发马达振动
   */
  public timeVibration(){
    try {
      // 触发马达振动
      vibrator.startVibration({
        type: 'time',
        duration: 1000,
      }, {
        id: 0,
        usage: 'alarm'
      }, (error: BusinessError) => {
        if (error) {
          console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
          return;
        }
        console.info('Succeed in starting vibration');
      });
    } catch (err) {
      let e: BusinessError = err as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }
  }

  /**
   * 按照预置振动效果触发马达振动,可先查询振动效果是否被支持,再调用振动接口
   */
  public typeVibration(){

    try {
      // 查询是否支持'haptic.clock.timer'
      vibrator.isSupportEffect('haptic.clock.timer', (err: BusinessError, state: boolean) => {
        if (err) {
          console.error(`Failed to query effect. Code: ${err.code}, message: ${err.message}`);
          return;
        }
        console.info('Succeed in querying effect');
        if (state) {
          try {
            // 触发马达振动
            vibrator.startVibration({
              type: 'preset',
              effectId: 'haptic.clock.timer',
              count: 1,
            }, {
              usage: 'unknown'
            }, (error: BusinessError) => {
              if (error) {
                console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
              } else {
                console.info('Succeed in starting vibration');
              }
            });
          } catch (error) {
            let e: BusinessError = error as BusinessError;
            console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
          }
        }
      })
    } catch (error) {
      let e: BusinessError = error as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }
  }

  public fileVibration(){
    const fileName: string = 'vibration.json';

    // 获取文件资源描述符
    let rawFd: resourceManager.RawFileDescriptor = getContext().resourceManager.getRawFdSync(fileName);

    // 触发马达振动
    try {
      vibrator.startVibration({
        type: "file",
        hapticFd: { fd: rawFd.fd, offset: rawFd.offset, length: rawFd.length }
      }, {
        id: 0,
        usage: 'alarm'
      }, (error: BusinessError) => {
        if (error) {
          console.error(`Failed to start vibration. Code: ${error.code}, message: ${error.message}`);
          return;
        }
        console.info('Succeed in starting vibration');
      });
    } catch (err) {
      let e: BusinessError = err as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }

    // 关闭文件资源描述符
    getContext().resourceManager.closeRawFdSync(fileName);
  }

  /**
   * 按照指定模式停止对应的马达振动,自定义振动不支持此类停止方式
   */
  public stopVibrationByType(){
    //  停止固定时长振动
    try {
      // 按照VIBRATOR_STOP_MODE_TIME模式停止振动
      vibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_TIME, (error: BusinessError) => {
        if (error) {
          console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
          return;
        }
        console.info('Succeed in stopping vibration');
      })
    } catch (err) {
      let e: BusinessError = err as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }

    // 停止预置振动:
    try {
      // 按照VIBRATOR_STOP_MODE_PRESET模式停止振动
      vibrator.stopVibration(vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_PRESET, (error: BusinessError) => {
        if (error) {
          console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
          return;
        }
        console.info('Succeed in stopping vibration');
      })
    } catch (err) {
      let e: BusinessError = err as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }

  }

  /**
   * 停止所有模式的马达振动,包括自定义振动:
   */
  public stopVibration(){
    try {
      // 停止所有模式的马达振动
      vibrator.stopVibration((error: BusinessError) => {
        if (error) {
          console.error(`Failed to stop vibration. Code: ${error.code}, message: ${error.message}`);
          return;
        }
        console.info('Succeed in stopping vibration');
      })
    } catch (error) {
      let e: BusinessError = error as BusinessError;
      console.error(`An unexpected error occurred. Code: ${e.code}, message: ${e.message}`);
    }
  }


}

振动配置文件:

dart 复制代码
{
  "MetaData": {
    "Create": "2023-01-09",
    "Description": "a haptic case",
    "Version": 1.0,
    "ChannelNumber": 1
  },
  "Channels": [
    {
      "Parameters": {
        "Index": 0
      },
      "Pattern": [
        {
          "Event": {
            "Type": "transient",
            "StartTime": 0,
            "Parameters": {
              "Frequency": 31,
              "Intensity": 100
            }
          }
        },
        {
          "Event": {
            "Type": "continuous",
            "StartTime": 40,
            "Duration": 54,
            "Parameters": {
              "Frequency": 30,
              "Intensity": 38,
              "Curve": [
                {
                  "Time": 0,
                  "Frequency": 0,
                  "Intensity": 0
                },
                {
                  "Time": 1,
                  "Frequency": 15,
                  "Intensity": 0.5
                },
                {
                  "Time": 40,
                  "Frequency": -8,
                  "Intensity": 1.0
                },
                {
                  "Time": 54,
                  "Frequency": 0,
                  "Intensity": 0
                }
              ]
            }
          }
        }
      ]
    }
  ]
}
相关推荐
王码码203521 分钟前
Flutter 三方库 sparky 的鸿蒙化适配指南 - 实现极简 2D 游戏引擎功能、支持高效精灵图渲染与跨端游戏逻辑
flutter·harmonyos·鸿蒙·openharmony
人工智能知识库24 分钟前
华为人工智能HCIP-AI Solution Architect H13-323题库(26年最新,带解析知识点)
华为·hcip·题库·hcip-ai·h13-323
Industio_触觉智能2 小时前
【转载】2026数字中国信创赛道【开放原子电鸿专项赛】开启报名,触觉智能电鸿硬件
信创·openharmony·rk3568·国产化·开源鸿蒙·电鸿·电力鸿蒙
特立独行的猫a4 小时前
OpenHarmony海思WS63星闪平台:Opus 音频编解码库介绍与海思 WS63 平台移植
驱动开发·移植·openharmony·星闪·opus·ws63
●VON5 小时前
Flutter组件通信详解:父子组件交互的最佳实践
javascript·flutter·华为·交互·harmonyos·von
Alter12305 小时前
华为吴辉:AI正在重构生产系统,“大增量时代”已经到来
人工智能·华为·重构
特立独行的猫a5 小时前
OpenHarmony海思WS63星闪平台:EasyLogger 移植到海思 WS63 平台完整指南
驱动开发·openharmony·ws63·hi3863·easylogger
枫叶丹46 小时前
【HarmonyOS 6.0】OAID服务正式支持TV设备
开发语言·华为·harmonyos
前端不太难6 小时前
鸿蒙游戏上线全流程(开发 + 打包 + 发布)
游戏·状态模式·harmonyos
木斯佳7 小时前
HarmonyOS 6 SDK对接实战:从原生ASR到Copilot SDK(下)- Copilot SDK对接与重构(全网最新)
ai·重构·copilot·harmonyos