ReactNative项目OpenHarmony三方库集成实战:react-native-haptic-feedback

欢迎加入开源鸿蒙跨平台社区 :https://openharmonycrossplatform.csdn.net

📋 前言

在移动应用开发中,触觉反馈(Haptic Feedback)已经成为提升用户体验的重要手段之一。当用户点击按钮、滑动列表或完成某个操作时,设备产生的震动反馈能够提供直观的物理响应,增强交互的真实感和满足感。react-native-haptic-feedback 是 React Native 生态中最流行的触觉反馈库,提供了丰富的震动效果类型和跨平台支持。

🎯 库简介

基本信息

  • 库名称 : react-native-haptic-feedback
  • 版本信息 :
    • <=2.2.1 + @react-native-oh-tpl/react-native-haptic-feedback: 支持 RN 0.72 版本 (已废弃)
    • 2.2.2 + @react-native-ohos/react-native-haptic-feedback: 支持 RN 0.72 版本
    • 2.3.4 + @react-native-ohos/react-native-haptic-feedback: 支持 RN 0.77 版本
  • 官方仓库: https://github.com/mkuczera/react-native-haptic-feedback
  • 鸿蒙仓库: https://github.com/react-native-oh-library/react-native-haptic-feedback
  • 主要功能 :
    • 📳 多种预设震动效果
    • 🎚️ 自定义震动强度
    • 🎼 自定义震动模式
    • 📱 iOS Core Haptics 支持
    • 🤖 Android Vibrator API 支持
    • 🎣 React Hook 支持

为什么需要触觉反馈?

场景 无触觉反馈 有触觉反馈
按钮点击 ⚠️ 缺乏确认感 ✅ 明确的操作反馈
滑动选择 ⚠️ 边界感知弱 ✅ 清晰的分段反馈
错误提示 ⚠️ 仅视觉提示 ✅ 视觉+触觉双重提示
成功操作 ⚠️ 反馈不明显 ✅ 满足感更强
游戏交互 ⚠️ 沉浸感不足 ✅ 增强沉浸体验

支持的震动类型

类型 说明 iOS Android HarmonyOS
impactLight 轻量冲击 ✅ ✅ ✅
impactMedium 中等冲击 ✅ ✅ ✅
impactHeavy 重度冲击 ✅ ✅ ✅
rigid 刚性冲击 ✅ ✅ ✅
soft 柔和冲击 ✅ ✅ ✅
notificationSuccess 通知成功 ✅ ✅ ✅
notificationWarning 通知警告 ✅ ✅ ✅
notificationError 通知错误 ✅ ✅ ✅
selection 选择反馈 ✅ ✅ ✅
clockTick 时钟滴答 ✅ ✅ ✅
contextClick 上下文点击 ✅ ✅ ✅
keyboardPress 键盘按下 ✅ ✅ ✅
keyboardRelease 键盘释放 ✅ ✅ ✅
keyboardTap 键盘点击 ✅ ✅ ✅
longPress 长按反馈 ✅ ✅ ✅
textHandleMove 文本手柄移动 ✅ ✅ ✅
virtualKey 虚拟按键 ✅ ✅ ✅
virtualKeyRelease 虚拟按键释放 ✅ ✅ ✅
effectClick 效果点击 ✅ ✅ ✅
effectDoubleClick 效果双击 ✅ ✅ ✅
effectHeavyClick 效果重击 ✅ ✅ ✅
effectTick 效果滴答 ✅ ✅ ✅

兼容性验证

在以下环境验证通过:

  • RNOH : 0.72.96; SDK : HarmonyOS 6.0.0 Release SDK; IDE : DevEco Studio 6.0.0.858; ROM: 6.0.0.112
  • RNOH : 0.72.33; SDK : HarmonyOS NEXT B1; IDE : DevEco Studio 5.0.3.900; ROM: Next.0.0.71
  • RNOH : 0.77.18; SDK : HarmonyOS 6.0.0 Release SDK; IDE : DevEco Studio 6.0.0.858; ROM: 6.0.0.112

📦 安装步骤

1. 安装依赖

在项目根目录执行以下命令,本文基于 RN 0.72.90 版本开发:

bash 复制代码
# RN 0.72 版本
npm install @react-native-ohos/react-native-haptic-feedback@2.2.2-rc.1

# 或者使用 yarn
yarn add @react-native-ohos/react-native-haptic-feedback@2.2.2-rc.1

2. 验证安装

安装完成后,检查 package.json 文件,应该能看到新增的依赖:

json 复制代码
{
  "dependencies": {
    "@react-native-ohos/react-native-haptic-feedback": "2.2.2-rc.1"
  }
}

🔧 HarmonyOS 平台配置 ⭐

由于 HarmonyOS 暂不支持 AutoLink,需要手动配置原生端代码。本文提供 HAR 包引入 和 源码引入 两种方式,可根据实际需求选择。

1. 在工程根目录的 oh-package.json5 添加 overrides 字段

打开 harmony/oh-package.json5,添加以下配置:

json5 复制代码
{
  // ... 其他配置
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

2. 权限声明

打开 harmony/entry/src/main/module.json5,声明振动权限:

json5 复制代码
{
  "module": {
    "requestPermissions": [
      // ... 其他权限
      {
        "name": "ohos.permission.VIBRATE"
      }
    ]
  }
}

💡 注意 :ohos.permission.VIBRATE 是 normal 级别权限,无需特殊签名配置。


方式一:HAR 包引入(推荐)📦

HAR 包引入方式简单快捷,适合大多数场景。

💡 提示 :HAR 包位于三方库安装路径的 harmony 文件夹下。

3.1 在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json5 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-ohos/react-native-haptic-feedback": "file:../../node_modules/@react-native-ohos/react-native-haptic-feedback/harmony/haptic_feedback.har"
}

3.2 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

3.3 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加以下配置:

cmake 复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error- unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 HapticFeedback 模块(HAR方式)
add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-haptic-feedback/src/main/cpp" ./haptic-feedback)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 HapticFeedback 库
target_link_libraries(rnoh_app PUBLIC rnoh_haptic_feedback)

3.4 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

cpp 复制代码
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "RNHapticFeedbackPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<RNHapticFeedbackPackage>(ctx),
    };
}

3.5 在 ArkTs 侧引入 Package

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

typescript 复制代码
import type { RNPackageContext, RNPackage } from 'rnoh/ts';
import { RNHapticFeedbackPackage } from '@react-native-ohos/react-native-haptic-feedback/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    // ... 其他包
    new RNHapticFeedbackPackage(ctx),
  ];
}

方式二:源码引入 📁

源码引入方式适合需要调试或修改原生代码的场景。

3.1 复制源码到 harmony 工程根目录

把 <RN工程>/node_modules/@react-native-ohos/react-native-haptic-feedback/harmony 目录下的源码 haptic_feedback 复制到 harmony(鸿蒙壳工程)工程根目录下。

bash 复制代码
# 复制源码目录
cp -r node_modules/@react-native-ohos/react-native-haptic-feedback/harmony/haptic_feedback harmony/

3.2 在 build-profile.json5 添加模块

打开 harmony/build-profile.json5,添加以下模块:

json5 复制代码
modules: [
  // ... 其他模块
  {
    name: 'haptic_feedback',
    srcPath: './haptic_feedback',
  }
]

💡 提示 :如果存在 build-profile.template.json5 文件,也需要同步添加上述模块配置。

3.3 修改 haptic_feedback/oh-package.json5

打开 harmony/haptic_feedback/oh-package.json5,修改 react-native-openharmony 版本与项目版本一致:

json5 复制代码
{
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

3.4 在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json5 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-ohos/react-native-haptic-feedback": "file:../haptic_feedback"
}

3.5 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

3.6 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加以下配置:

cmake 复制代码
project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error- unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 HapticFeedback 模块(源码方式)
add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-haptic-feedback/src/main/cpp" ./haptic-feedback)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 HapticFeedback 库
target_link_libraries(rnoh_app PUBLIC rnoh_haptic_feedback)

3.7 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

cpp 复制代码
#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "RNHapticFeedbackPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<RNHapticFeedbackPackage>(ctx),
    };
}

3.8 在 ArkTs 侧引入 Package

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

typescript 复制代码
import type { RNPackageContext, RNPackage } from 'rnoh/ts';
import { RNHapticFeedbackPackage } from '@react-native-ohos/react-native-haptic-feedback/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    // ... 其他包
    new RNHapticFeedbackPackage(ctx),
  ];
}

同步并运行 🚀

4. 同步依赖

点击 DevEco Studio 右上角的 sync 按钮,或者在终端执行:

bash 复制代码
cd harmony/entry
ohpm install

然后编译、运行即可。

📖 API 详解

trigger(method, options)

触发触觉反馈。

参数说明:

参数 类型 必填 说明
method string ✅ 震动类型
options object ❌ 配置选项

options 配置:

属性 类型 默认值 说明
enableVibrateFallback boolean false 在不支持触觉反馈时是否使用普通震动
ignoreAndroidSystemSettings boolean false 是否忽略 Android 系统震动设置

使用示例:

typescript 复制代码
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

// 基础用法
ReactNativeHapticFeedback.trigger('impactLight');

// 带配置项
ReactNativeHapticFeedback.trigger('impactMedium', {
  enableVibrateFallback: true,
  ignoreAndroidSystemSettings: false,
});

震动类型分类

冲击反馈(Impact)

适用于按钮点击、UI 元素交互等场景。

类型 说明 使用场景
impactLight 轻量冲击 轻量级交互
impactMedium 中等冲击 常规按钮点击
impactHeavy 重度冲击 重要操作确认
rigid 刚性冲击 尖锐、快速的反馈
soft 柔和冲击 温柔、舒缓的反馈
通知反馈(Notification)

适用于操作结果提示。

类型 说明 使用场景
notificationSuccess 成功通知 操作成功提示
notificationWarning 警告通知 警告提示
notificationError 错误通知 错误提示
选择反馈(Selection)

适用于选择器、滚动列表等场景。

类型 说明 使用场景
selection 选择反馈 选择器滚动
clockTick 时钟滴答 时钟计时
contextClick 上下文点击 上下文菜单
键盘反馈(Keyboard)

适用于键盘输入场景。

类型 说明 使用场景
keyboardPress 键盘按下 按键按下
keyboardRelease 键盘释放 按键释放
keyboardTap 键盘点击 按键点击
交互反馈(Interaction)

适用于长按、拖动等场景。

类型 说明 使用场景
longPress 长按反馈 长按触发
textHandleMove 文本手柄移动 文本选择
virtualKey 虚拟按键 虚拟按键按下
virtualKeyRelease 虚拟按键释放 虚拟按键释放
效果反馈(Effect)

适用于通用交互效果。

类型 说明 使用场景
effectClick 效果点击 标准点击
effectDoubleClick 效果双击 双击操作
effectHeavyClick 效果重击 重击操作
effectTick 效果滴答 滴答效果

📱 完整示例(请确认在手机设置中打开了系统触觉反馈功能)

以下是一个完整的触觉反馈演示应用:

typescript 复制代码
import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  ScrollView,
  Switch,
  Alert,
  Platform,
} from 'react-native';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

type HapticFeedbackTypes =
  | 'impactLight'
  | 'impactMedium'
  | 'impactHeavy'
  | 'rigid'
  | 'soft'
  | 'notificationSuccess'
  | 'notificationWarning'
  | 'notificationError'
  | 'selection'
  | 'clockTick'
  | 'contextClick'
  | 'keyboardPress'
  | 'keyboardRelease'
  | 'keyboardTap'
  | 'longPress'
  | 'textHandleMove'
  | 'virtualKey'
  | 'virtualKeyRelease'
  | 'effectClick'
  | 'effectDoubleClick'
  | 'effectHeavyClick'
  | 'effectTick';

interface HapticButtonProps {
  title: string;
  type: HapticFeedbackTypes;
  description: string;
  enabled?: boolean;
}

const HapticButton: React.FC<HapticButtonProps> = ({ title, type, description, enabled }) => {
  const handlePress = () => {
    if (!enabled) {
      Alert.alert('提示', '请先启用触觉反馈');
      return;
    }
    ReactNativeHapticFeedback.trigger(type, {
      enableVibrateFallback: true,
      ignoreAndroidSystemSettings: false,
    });
    Alert.alert('触觉反馈', `${title}\n${description}`);
  };

  return (
    <TouchableOpacity 
      style={[styles.hapticButton, !enabled && styles.disabledButton]} 
      onPress={handlePress} 
      activeOpacity={0.7}
    >
      <Text style={[styles.buttonTitle, !enabled && styles.disabledText]}>{title}</Text>
      <Text style={styles.buttonDesc}>{description}</Text>
    </TouchableOpacity>
  );
};

const HapticFeedbackDemo: React.FC = () => {
  const [hapticsEnabled, setHapticsEnabled] = useState(true);

  const toggleHaptics = (value: boolean) => {
    setHapticsEnabled(value);
    if (value) {
      ReactNativeHapticFeedback.trigger('impactLight', {
        enableVibrateFallback: true,
      });
    }
  };

  const impactTypes: HapticButtonProps[] = [
    { title: '轻量冲击', type: 'impactLight', description: '轻柔的触觉反馈' },
    { title: '中等冲击', type: 'impactMedium', description: '适中的触觉反馈' },
    { title: '重度冲击', type: 'impactHeavy', description: '强烈的触觉反馈' },
    { title: '刚性冲击', type: 'rigid', description: '尖锐的触觉反馈' },
    { title: '柔和冲击', type: 'soft', description: '柔和的触觉反馈' },
  ];

  const notificationTypes: HapticButtonProps[] = [
    { title: '成功通知', type: 'notificationSuccess', description: '操作成功提示' },
    { title: '警告通知', type: 'notificationWarning', description: '警告提示' },
    { title: '错误通知', type: 'notificationError', description: '错误提示' },
  ];

  const interactionTypes: HapticButtonProps[] = [
    { title: '选择反馈', type: 'selection', description: '选择器滚动' },
    { title: '时钟滴答', type: 'clockTick', description: '时钟计时' },
    { title: '长按反馈', type: 'longPress', description: '长按触发' },
    { title: '键盘按下', type: 'keyboardPress', description: '键盘输入' },
  ];

  const effectTypes: HapticButtonProps[] = [
    { title: '效果点击', type: 'effectClick', description: '标准点击效果' },
    { title: '效果双击', type: 'effectDoubleClick', description: '双击效果' },
    { title: '效果重击', type: 'effectHeavyClick', description: '重击效果' },
    { title: '效果滴答', type: 'effectTick', description: '滴答效果' },
  ];

  return (
    <ScrollView style={styles.container}>
      <View style={styles.settingSection}>
        <View style={styles.settingRow}>
          <Text style={styles.settingLabel}>启用触觉反馈</Text>
          <Switch
            value={hapticsEnabled}
            onValueChange={toggleHaptics}
            trackColor={{ false: '#767577', true: '#81b0ff' }}
            thumbColor={hapticsEnabled ? '#007AFF' : '#f4f3f4'}
          />
        </View>
        <Text style={styles.hint}>
          ⚠️ 请确保系统设置中的震动功能已开启
        </Text>
      </View>

      <View style={styles.section}>
        <Text style={styles.sectionTitle}>💪 冲击反馈</Text>
        <View style={styles.buttonGrid}>
          {impactTypes.map((item) => (
            <HapticButton key={item.type} {...item} enabled={hapticsEnabled} />
          ))}
        </View>
      </View>

      <View style={styles.section}>
        <Text style={styles.sectionTitle}>📢 通知反馈</Text>
        <View style={styles.buttonGrid}>
          {notificationTypes.map((item) => (
            <HapticButton key={item.type} {...item} enabled={hapticsEnabled} />
          ))}
        </View>
      </View>

      <View style={styles.section}>
        <Text style={styles.sectionTitle}>👆 交互反馈</Text>
        <View style={styles.buttonGrid}>
          {interactionTypes.map((item) => (
            <HapticButton key={item.type} {...item} enabled={hapticsEnabled} />
          ))}
        </View>
      </View>

      <View style={styles.section}>
        <Text style={styles.sectionTitle}>✨ 效果反馈</Text>
        <View style={styles.buttonGrid}>
          {effectTypes.map((item) => (
            <HapticButton key={item.type} {...item} enabled={hapticsEnabled} />
          ))}
        </View>
      </View>

      <View style={styles.footer}>
        <Text style={styles.footerText}>
          💡 提示:请在真机上测试以体验触觉反馈效果
        </Text>
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  settingSection: {
    backgroundColor: '#fff',
    padding: 16,
    marginBottom: 12,
  },
  settingRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  settingLabel: {
    fontSize: 16,
    color: '#333',
  },
  hint: {
    fontSize: 12,
    color: '#999',
    marginTop: 8,
  },
  section: {
    backgroundColor: '#fff',
    padding: 16,
    marginBottom: 12,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    color: '#333',
    marginBottom: 12,
  },
  buttonGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    marginHorizontal: -6,
  },
  hapticButton: {
    width: '48%',
    marginHorizontal: '1%',
    marginBottom: 12,
    padding: 16,
    backgroundColor: '#f0f8ff',
    borderRadius: 12,
    borderWidth: 1,
    borderColor: '#007AFF',
  },
  disabledButton: {
    backgroundColor: '#f5f5f5',
    borderColor: '#ccc',
  },
  disabledText: {
    color: '#999',
  },
  buttonTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#007AFF',
    marginBottom: 4,
  },
  buttonDesc: {
    fontSize: 12,
    color: '#666',
  },
  footer: {
    padding: 20,
    alignItems: 'center',
  },
  footerText: {
    fontSize: 14,
    color: '#666',
    textAlign: 'center',
  },
});

export default HapticFeedbackDemo;

🔬 高级用法

1. 按钮组件集成

typescript 复制代码
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

interface HapticButtonProps {
  title: string;
  onPress: () => void;
  hapticType?: 'impactLight' | 'impactMedium' | 'impactHeavy';
}

export const HapticButton: React.FC<HapticButtonProps> = ({
  title,
  onPress,
  hapticType = 'impactLight',
}) => {
  const handlePress = () => {
    ReactNativeHapticFeedback.trigger(hapticType, {
      enableVibrateFallback: true,
    });
    onPress();
  };

  return (
    <TouchableOpacity style={styles.button} onPress={handlePress}>
      <Text style={styles.text}>{title}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  button: {
    padding: 16,
    backgroundColor: '#007AFF',
    borderRadius: 8,
    alignItems: 'center',
  },
  text: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});

2. 滑动选择器集成

typescript 复制代码
import { ScrollView, Text, StyleSheet } from 'react-native';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

const HapticPicker: React.FC = () => {
  const items = ['选项1', '选项2', '选项3', '选项4', '选项5'];
  let lastItemIndex = -1;

  const handleScroll = (event: any) => {
    const contentOffset = event.nativeEvent.contentOffset.x;
    const itemWidth = 100;
    const currentIndex = Math.round(contentOffset / itemWidth);

    if (currentIndex !== lastItemIndex && currentIndex >= 0) {
      ReactNativeHapticFeedback.trigger('selection', {
        enableVibrateFallback: true,
      });
      lastItemIndex = currentIndex;
    }
  };

  return (
    <ScrollView
      horizontal
      pagingEnabled
      onScroll={handleScroll}
      scrollEventThrottle={16}
      style={styles.container}
    >
      {items.map((item, index) => (
        <Text key={index} style={styles.item}>
          {item}
        </Text>
      ))}
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    height: 60,
  },
  item: {
    width: 100,
    textAlign: 'center',
    lineHeight: 60,
    fontSize: 16,
  },
});

3. React Hook 封装

typescript 复制代码
import { useCallback, useState } from 'react';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

type HapticType =
  | 'impactLight'
  | 'impactMedium'
  | 'impactHeavy'
  | 'notificationSuccess'
  | 'notificationWarning'
  | 'notificationError'
  | 'selection';

interface HapticOptions {
  enableVibrateFallback?: boolean;
  ignoreAndroidSystemSettings?: boolean;
}

export const useHaptic = (defaultOptions?: HapticOptions) => {
  const [enabled, setEnabled] = useState(true);

  const trigger = useCallback(
    (type: HapticType, options?: HapticOptions) => {
      if (enabled) {
        ReactNativeHapticFeedback.trigger(type, {
          enableVibrateFallback: true,
          ignoreAndroidSystemSettings: false,
          ...defaultOptions,
          ...options,
        });
      }
    },
    [enabled, defaultOptions]
  );

  return {
    trigger,
    enabled,
    setEnabled,
  };
};

// 使用示例
const MyComponent = () => {
  const { trigger, enabled, setEnabled } = useHaptic({
    enableVibrateFallback: true,
  });

  return (
    <TouchableOpacity onPress={() => trigger('impactMedium')}>
      <Text>点击我</Text>
    </TouchableOpacity>
  );
};

⚠️ 常见问题

Q1: 震动没有反馈?

解决方案:

  1. 检查权限是否正确声明
  2. 确认在真机上测试(模拟器不支持)
  3. 检查设备是否开启了震动功能

Q2: 震动效果不一致?

解决方案:

  • 不同设备的震动马达性能不同
  • HarmonyOS 对各类型震动有统一实现

📚 参考资料

相关推荐
admin and root7 小时前
「AI安全篇」实战AntiDebug自动化JS逆向加解密MCP
javascript·人工智能·网络安全·自动化·漏洞挖掘·cnvd·src赏金
wengad9 小时前
从 wangEditor 迁到 wangEditor-next
前端·javascript·vue.js
行者-全栈开发10 小时前
【前端/JS框架】CVE-2026-3854:GitHub Enterprise Server X-Stat注入XSS漏洞深度剖析与紧急修复指南
前端·javascript·github
怕浪猫12 小时前
2026年金九银十,我面了22个前端
前端·javascript·面试
前端的日常12 小时前
一个人+AI做情侣食谱小程序,30天纯赚
前端·javascript·后端
是你的小橘呀12 小时前
React Native 3:useEffect 自动请求接口 + 搜索功能 + 封装 Loading 组件
react native
qq_3168377512 小时前
阿里云百炼 fun-asr-realtime uniapp vue3 调用
javascript·vue.js·uni-app
默_笙13 小时前
🚊 别再让 AI 的记忆写两遍了:PostgreSQL 把关系查询和语义检索装进一张表
前端·javascript
lzhdim13 小时前
C#不为人知的10个魔法特性:资深开发者也会震惊的底层奥秘
java·前端·javascript·算法·c#
是你的小橘呀13 小时前
React Native 2:列表渲染 + 后端接口搭建 + Fetch 请求数据
react native