@hadss/react_native_uni_input
v1.0.0-rc.0
Published
A library that encapsulates Hongmeng gestures and RN native gestures, supporting Hongmeng, Android, and iOS platforms.
Readme
@hadss/react_native_uni_input
介绍
这是一个封装了ArkUI手势功能并与react-native-gesture-handler库相结合的跨平台手势解决方案,旨在为OpenHarmony、Android和ios平台提供一致的手势交互体验。该库通过Fabric架构将ArkUI的原生手势能力桥接到React Native中,并在底层使用Platform.OS判断当前运行环境:当应用运行在OpenHarmony平台时,自动启用ArkUI提供的手势支持;而在Android或ios等非OpenHarmony平台下,则会使用 react-native-gesture-handler作为手势处理引擎。从而实现了在三大平台上统一且高性能的手势行为与交互逻辑,同时也封装了RN中常用的组件react-native-popup-menu。
工程目录
react_native_uni_input
├─harmony
│ ├─gesture.har // gesutre代码打包产物
│ └─gesture
│ └─src/main
│ ├─cpp
| | ├─CMakeLists.txt // fabric组件CAPI侧,代码信息
| | ├─GestureEventsViewComponentInstance.cpp // fabric组件CAPI侧,创建手势相关node及处理逻辑实现
| | ├─GestureEventsViewComponentInstance.h // fabric组件CAPI侧,创建手势相关node及处理逻辑定义
| | ├─GesturePackage.cpp // fabric组件CAPI侧,创建包桥接代码实现
| | ├─GesturePackage.h // fabric组件CAPI侧,创建包桥接代码定义
| | ├─Index.d.ts // 空实现,为了打包c++代码
| | ├─ViewWithKeyEventComponentInstance.cpp // fabric组件CAPI侧,创建按键监听node及相关处理逻辑实现
| | ├─ViewWithKeyEventComponentInstance.h // fabric组件CAPI侧,创建按键监听node及相关处理逻辑定义
| | ├─ViewWithKeyEventComponentInstance.cpp // fabric组件CAPI侧,创建鼠标监听node及相关处理逻辑实现
| | ├─ViewWithKeyEventComponentInstance.h // fabric组件CAPI侧,创建鼠标监听node及相关处理逻辑定义
| | └─oh-package.json5 // fabric组件CAPI侧,项目信息
│ └─module.json5 // 模块信息
├─native
│ ├─harmonyGesture.ts // 创建OpenHarmony平台手势方法
│ └─nativeGesture.ts // 创建非OpenHarmony平台手势方法
├─src
│ ├─components
| | └─GestureWrapper.tsx // 创建手势组件
│ ├─specs/v2
│ | ├─GestureNativeComponent // fabric组件手势RN侧定义
│ | ├─ViewWithKeyEventNativeComponent // fabric组件按键监听RN侧定义
│ | └─ViewWithMouseEventNativeComponent // fabric组件鼠标监听RN侧定义
| └─factory.ts // 创建手势入口
└─index.ts // 库导出文件安装与使用
注意: 本库依赖react-native-gesture-handler及react-native-popup-menu, 在安装本库时需同时安装相应的库。 本库暂未上传到npm仓库,目前使用时需进入到工程目录,运行npm pack获取tgz包,然后安装。
进入到工程目录并输入以下命令:
npm
npm install @hadss/react_native_uni_input
npm install react-native-gesture-handler
npm install react-native-popup-menuyarn
yarn add @hadss/react_native_uni_input
yarn add react-native-gesture-handler
yarn add react-native-popup-menu使用示例
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native';
import {
GestureDetector,
Gesture,
MenuProvider,
Menu,
MenuOptions,
MenuOption,
MenuTrigger,
ViewWithKeyEvent,
ViewWithMouseEvent,
} from '@hadss/react_native_uni_input';
const App = () => {
const [tapCount, setTapCount] = React.useState(1);
const [keyEventStr, setKeyEventStr] = React.useState('123');
const [mouseEventStr, setMouseEventStr] = React.useState('456');
const onTapGesture = Gesture.Tap()
.minPointers(1)
.numberOfTaps(tapCount)
.onStart(() => {
console.log('Tapped!');
});
const onDoubleGesture = Gesture.Tap()
.minPointers(1)
.numberOfTaps(2)
.onStart(() => {
console.log('Double Tapped!');
});
const multiGesture = Gesture.Simultaneous(onTapGesture, onDoubleGesture);
const keyEvent = (event: {nativeEvent: any}) => {
console.log('Key Event:', event.nativeEvent);
setKeyEventStr(JSON.stringify(event.nativeEvent));
};
const mouseEvent = (event: {nativeEvent: any}) => {
console.log('Mouse Event:', event.nativeEvent);
setMouseEventStr(JSON.stringify(event.nativeEvent));
};
return (
<View
style={{
display: 'flex',
flex: 1,
padding: 10,
backgroundColor: '#f1f3f5',
flexDirection: 'row',
flexWrap: 'wrap',
gap: 10,
}}>
<GestureDetector gesture={onTapGesture}>
<View style={styles.container}>
<Text style={styles.text}>Tap me</Text>
</View>
</GestureDetector>
<GestureDetector gesture={multiGesture}>
<View style={styles.container}>
<Text style={styles.text}>multiGesture</Text>
</View>
</GestureDetector>
<ViewWithKeyEvent onKeyEvent={keyEvent}>
<View style={styles.container}>
<Text>{keyEventStr}</Text>
</View>
</ViewWithKeyEvent>
<ViewWithMouseEvent onMouseEvent={mouseEvent}>
<View style={styles.container}>
<Text>{mouseEventStr}</Text>
</View>
</ViewWithMouseEvent>
<TouchableOpacity
style={styles.container}
onPress={() => setTapCount(tapCount === 1 ? 2 : 1)}>
<Text style={styles.text}>改变Tap手势触发条件: {tapCount}</Text>
</TouchableOpacity>
<View style={styles.container}>
<View style={{width: 200, height: 200, backgroundColor: 'lightgray'}}>
<MenuProvider skipInstanceCheck={true}>
<View>
<Text>Hello world!</Text>
<Menu>
<MenuTrigger text="Select action" />
<MenuOptions>
<MenuOption
onSelect={() => Alert.alert('Save')}
text="Save"
/>
<MenuOption onSelect={() => Alert.alert('Delete')}>
<Text style={{color: 'red'}}>Delete</Text>
</MenuOption>
<MenuOption
onSelect={() => Alert.alert('Not called')}
disabled={true}
text="Disabled"
/>
</MenuOptions>
</Menu>
</View>
</MenuProvider>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
width: 200,
height: 200,
backgroundColor: '#e0e0e0',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
borderWidth: 1,
},
text: {
fontSize: 18,
color: '#333',
},
});
export default App;
Link
目前OpenHarmony暂不支持AutoLink,所以Link步骤需要手动配置。
首先需要使用DevEco Studio打开项目里的OpenHarmony工程,在工程根目录的oh-package.json5添加overrides字段:
{
"overrides": {
"@rnoh/react-native-openharmony": "./react_native_openharmony"
}
}引入原生端代码
目前有两种方法:
通过har包引入(在IDE完善相关功能后该方法会被遗弃,目前首选此方法)。
说明: har包位于三方库安装路径的
harmony文件夹下。a. 打开
entry/oh-package.json5,添加以下依赖:{ "dependencies":{ "@rnoh/react-native-openharmony": "file:../react_native_openharmony", "gesture": "file:../../node_modules/@hadss/react_native_uni_input/harmony/gesture.har", } }b. 配置CMakeLists和引入RNOHGeneratedPackage:
打开
entry/src/main/cpp/CMakeLists.txt,添加:project(rnapp) cmake_minimum_required(VERSION 3.4.1) set(CMAKE_SKIP_BUILD_RPATH TRUE) set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules") set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp") set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated") 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") add_compile_definitions(WITH_HITRACE_SYSTRACE) set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use + file(GLOB_RECURSE GENERATED_CPP_FILES "./generated/*.cpp") add_subdirectory("${RNOH_CPP_DIR}" ./rn) + add_subdirectory("${OH_MODULE_DIR}/gesture/src/main/cpp" ./gesture) add_library(rnoh_app SHARED + ${GENERATED_CPP_FILES} "./PackageProvider.cpp" "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" ) target_link_libraries(rnoh_app PUBLIC rnoh) + target_link_libraries(rnoh_app PUBLIC gesture)c. 打开
entry/src/main/cpp/PackageProvider.cpp,添加:#include "RNOH/PackageProvider.h" + #include "generated/RNOHGeneratedPackage.h" + #include "GesturePackage.h" using namespace rnoh; std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) { return { + std::make_shared<RNOHGeneratedPackage>(ctx), + std::make_shared<GesturePackage>(ctx), }; }d. 运行:
点击右上角的
sync按钮或者在终端执行:
cd entry ohpm install然后编译、运行即可。
说明 若项目启动时报错:can not find record '&@rnoh/react-native-openharmony/generated/ts&X.X.X'。需在entry\oh_modules@rnoh\react-native-openharmony\ts.ts文件中添加export * from './generated/ts',并删除.cxx文件夹、build文件夹,然后执行sync操作同步代码。
直接链接源码。
如需使用直接链接源码,请参考直接链接源码说明。
API
说明: "Platform"列表示支持的平台,All表示支持Android/ios/Openharmony平台。
GestureDetector
| Name | Description | Type | Platform | |-----------------------------------|----------------|----------|----------| | gesture | 一个对象,包含手势的参数及回调函数信息 | 基础手势 | All |
Gesture
| method | Description | Type | Platform | |-----------------------------------|----------------|----------|---------| | Gesture.Tap() | 创建点击手势 | function() | All | | Gesture.Pan() | 创建拖动手势 | function() | All | | Gesture.Rotation() | 创建旋转手势,暂不支持PC触控板上的双指旋转 | function() | All | | Gesture.LongPress() | 创建长按手势 | function() | All | | Gesture.Pinch() | 创建捏合手势 | function() | All | | Gesture.Fling() | 创建轻扫手势 | function() | All | | Gesture.Hover() | 创建悬浮手势 | function() | All | | Gesture.Simultaneous() | 创建并发识别手势,注册的手势同时识别,直到所有手势识别结束,手势识别互相不影响。 | function() | All | | Gesture.Race() | 创建顺序识别手势,按照手势的注册顺序识别手势,直到所有手势识别成功。若有一个手势识别失败,后续手势识别均失败。| function() | All | | Gesture.Exclusive() | 互斥识别,注册的手势同时识别,若有一个手势识别成功,则结束手势识别。| function() | All |
支持的方法
| 手势 | 参数 | 描述 | 类型 | openharmony | Android | ios |
|------------------|----------------|----------------------------------------------------------------------|---------------------------------|-------------|-----------|---------|
| Gesture.Tap() | numberOfTaps | 触发点击手势所需的点击次数 | number | 支持 | 支持 | 支持 |
| | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.LongPress() | repeat | 是否允许长按手势重复触发 | boolean | 支持 | 不支持 | 不支持 |
| | minDuration | 长按手势识别所需的最短持续时间(毫秒) | number | 支持 | 支持 | 支持 |
| | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onCancel | 手势取消时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onEnd | 手势结束时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.Pan() | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | minDistance | 触发拖动手势所需的最小距离 | number | 支持 | 支持 | 支持 |
| | direction | 定义手势的方向或方向组合, 可能的值有:'all', 'horizontal', 'vertical', 'left', 'right', 'up', 'down', 'none' 。也可以使用&和|组合 | string | 支持 | 不支持 | 不支持 |
| | onUpdate | 手势变化时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onCancel | 手势取消时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onEnd | 手势结束时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.Rotation() | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | minAngle | 触发旋转手势所需达到的最小角度 | number | 支持 | 不支持 | 不支持 |
| | onUpdate | 手势变化时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onCancel | 手势取消时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onEnd | 手势结束时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.Pinch() | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | minDistance | 触发缩放手势所需的最小距离 | number | 支持 | 不支持 | 不支持 |
| | onUpdate | 手势变化时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onCancel | 手势取消时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onEnd | 手势结束时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.Fling() | minPointers | 触发手势需要的手指数目 | number | 支持 | 支持 | 支持 |
| | minVelocity | 触发轻扫手势所需的最小速度 | number | 支持 | 支持 | 支持 |
| | direction | 定义手势的方向或方向组合, 可能的值有:'all', 'horizontal', 'vertical', 'left', 'right', 'up', 'down', 'none' 。也可以使用&和|组合,android及ios环境上仅支持'left', 'right', 'up', 'down',对应Direction的枚举值。 | string | 支持 | 支持 | 支持 |
| | onStart | 手势触发开始时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| | onCancel | 手势取消时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
| Gesture.Hover() | onHover | 悬浮手势触发时的回调 | (event: GestureEvent) => void | 支持 | 支持 | 支持 |
GestureEvent
| Name | Description | Type | Platform | |--------------|------------------------------------------------------------------------------------------------------|---------------|--------------| | fingers | 手势手指信息,最多10个 | FingerData[] | 仅OpenHarmony | | timestamp | 时间发生时间,单位ns | number | 仅OpenHarmony | | type | 事件类型 | string | 仅OpenHarmony | | velocityX | 当前手势的x轴方向速度,单位px/秒 | number | All | | velocityY | 当前手势的y轴方向速度,单位px/秒 | number | All | | velocity | 当前手势主方向速度,为xy轴方向速度的平方和的算数平方根,单位px/秒 | number | All | | translationX | 当前手势事件x轴相对偏移量,单位为px | number | All | | translationY | 滑动手势返回当前手势事件y轴相对偏移量 | number | All | | repeat | 长按手势是否重复触发,当前取值为创建手势传入的参数 | boolean | 仅OpenHarmony | | rotation | 旋转手势、轻扫手势返回当前手势事件角度信息,用弧度表示 | number | All | | focalX | 捏合手势中心点相对于当前组件元素左上角x轴坐标,单位为px | number | All | | focalY | 捏合手势中心点相对于当前组件元素左上角y轴坐标,单位为px | number | All | | scale | 捏合手势返回当前手势事件缩放比例 | number | All | | speed | 轻扫手势速度,即所有手指滑动的平均速度,单位为px/秒 | number | 仅OpenHarmony | | isHover | 悬浮事件,返回光标或触控笔是否悬浮在组件上 | boolean | All | | x | 当前手指相对于当前组件左上角的X坐标,OpenHarmony平台取的是第一个手指信息里的数据。 | number | All | | y | 当前手指相对于当前组件左上角的Y坐标,OpenHarmony平台取的是第一个手指信息里的数据。 | number | All | | absoluteX | 当前手指相对于当前应用窗口左上角的X坐标,OpenHarmony平台取的是第一个手指信息里的数据。 | number | All | | absoluteY | 当前手指相对于当前应用窗口左上角的Y坐标 ,OpenHarmony平台取的是第一个手指信息里的数据。 | number | All |
FingerData
| Name | Description | Type | Platform | |-------------|-------------------------------------------------------------------------------------------------------|---------------|--------------| | pointId | 从带有指向性的输入事件(如触摸事件、鼠标事件、轴事件)中获取多点触控的接触点标识 | number | OpenHarmony | | x | 当前手指相对于当前组件左上角的X坐标,如果参数异常则返回0.0f | number | OpenHarmony | | y | 当前手指相对于当前组件左上角的Y坐标,如果参数异常则返回0.0f | number | OpenHarmony | | windowX | 当前手指相对于当前应用窗口左上角的X坐标 | number | OpenHarmony | | windowY | 当前手指相对于当前应用窗口左上角的Y坐标 | number | OpenHarmony | | displayX | 相对于当前屏幕左上角的X坐标 | number | OpenHarmony | | displayY | 相对于当前屏幕左上角的Y坐标 | number | OpenHarmony | | tiltX | 从带有指向性的输入事件(如触摸事件)中获取相对YZ平面的角度,取值的范围[-90, 90],其中正值是向右倾斜 | number | OpenHarmony | | tiltY | 从指向性输入事件(如触摸事件)中获取相对XZ平面的角度,取值的范围[-90, 90],其中正值是向右倾斜。仅适用于支持倾角上报的触控笔操作产生的触控事件。 | number | OpenHarmony |
ViewWithMouseEvent
| Name | Description | Type | Platform | |------------|---------------------|----------------------------|--------------| | onMouseEvent | 触发鼠标事件时的回调 | (event: MouseEvent) => void | OpenHarmony |
MouseEvent
| Name | Description | Type | Platform | |-----------------|-------------------------------------------------------------------|---------------|--------------| | x | 鼠标位置相对于当前组件左上角的x轴坐标。 | number | OpenHarmony | | y | 鼠标位置相对于当前组件左上角的y轴坐标。 | number | OpenHarmony | | windowX | 鼠标位置相对于应用窗口左上角的x轴坐标。 | number | OpenHarmony | | windowY | 鼠标位置相对于应用窗口左上角的y轴坐标。 | number | OpenHarmony | | displayX | 鼠标位置相对于应用屏幕左上角的x轴坐标。 | number | OpenHarmony | | displayY | 鼠标位置相对于应用屏幕左上角的y轴坐标。 | number | OpenHarmony | | rawDeltaX | 相对于先前上报的鼠标指针位置的X轴偏移量。当鼠标指针处于屏幕边缘时,该值可能小于两次上报的X坐标之差。 | number | OpenHarmony | | rawDeltaY | 相对于先前上报的鼠标指针位置的Y轴偏移量。 | number | OpenHarmony | | action | 鼠标动作。1: 按下;2:松开;3:移动 | number | OpenHarmony | | button | 鼠标按键。1:左键;2:右键;0:移动; | number | OpenHarmony |
ViewWithKeyEvent
| Name | Description | Type | Platform | |------------|---------------------|----------------------------|--------------| | onKeyEvent | 触发按键事件时的回调 | (event: KeyEvent) => void | OpenHarmony |
KeyEvent
| Name | Description | Type | Platform | |-----------------|-------------------------------------------------------------------|---------------|--------------| | eventType | 按键类型,值:unknown、up、down | string | OpenHarmony | | keyCode | 按键的键码,具体键码对应按键参考:arkui_keycode | number | OpenHarmony | | keyValue | 按键的键值 | string | OpenHarmony | | keySourceType | 按键输入设备类型,值:unknown、mouse、keyboard、joystick | string | OpenHarmony |
react-native-popup-menu支持的组件及方法
react-native-popup-menu支持的组件及方法参考react-native-popup-menu。
约束与限制
- 本库依赖于react-native-gesture-handler,并在android SDK36及ios13上验证ok,其他android版本及ios版本使用时请参考源库对相应平台的约束与限制。
- DevEco Studio版本:DevEco Studio 5.0.5 Release及以上。
- SDK版本:API17及以上。
