@hadss/react_native_geometry_transition v1.0.6
@hadss/react_native_geometry_transition
介绍
为基于 React Native 的混合开发工程提供一镜到底能力。
工程目录
.
├── harmony
│ ├── geometry_transition
│ │ ├── src
│ │ │ └── main
│ │ │ ├── cpp // CAPI一镜到底组件实现
│ │ │ │ ├── CMakeLists.txt
│ │ │ │ ├── GeometryViewComponentDescriptor.h
│ │ │ │ ├── GeometryViewComponentInstance.cpp
│ │ │ │ ├── GeometryViewComponentInstance.h
│ │ │ │ ├── GeometryViewEventEmitter.cpp
│ │ │ │ ├── GeometryViewEventEmitter.h
│ │ │ │ ├── GeometryViewJSIBinder.h
│ │ │ │ ├── GeometryViewNode.cpp
│ │ │ │ ├── GeometryViewNode.h
│ │ │ │ ├── GeometryViewPackage.cpp
│ │ │ │ ├── GeometryViewPackage.h
│ │ │ │ ├── Index.d.ts
│ │ │ │ ├── Props.cpp
│ │ │ │ ├── Props.h
│ │ │ │ └── oh-package.json5
│ │ │ ├── ets // ArkTS一镜到底组件实现
│ │ │ │ ├── GeometryTransitionView.ets
│ │ │ │ ├── GeometryTransitionViewPackages.ts
│ │ │ │ └── generated
│ │ │ │ ├── components
│ │ │ │ │ ├── GeometryTransitionView.ts
│ │ │ │ │ └── ts.ts
│ │ │ │ ├── index.ets
│ │ │ │ ├── ts.ts
│ │ │ │ └── turboModules
│ │ │ │ └── ts.ts
│ │ │ └── module.json5
│ │ └── ts.ts
│ └── geometry_transition.har
├── package.json
├── src
│ ├── fabric
│ │ ├── GeometryView.tsx // CAPI一镜到底组件
│ │ └── v1
│ │ └── GeometryTransitionViewNativeComponent.tsx // ArkTS一镜到底组件
│ └── index.tsx安装与使用
进入到工程目录并输入以下命令:
npm
npm install @hadss/react_native_geometry_transitionyarn
yarn add @hadss/react_native_geometry_transition下面的代码展示了这个库的基本使用场景: 前置条件:ArkUI的navigation控制路由跳转,NavDestination加载对应的RN bundle。
场景一:当前页面是RN页面,目标页面是原生页面
PlayList页面
使用了GeometryView组件,并设置了geometryViewID为'test',点击事件调用原生navPathStack.pushPath,跳转MusicPlay页面。
function PlayList() {
return (
<SafeAreaView style={styles.container}>
<GeometryView
style={[styles.geometryView, { top: 100, left: 100 }]}
geometryViewID={'test'}
onGeometryViewClick={() => {
SampleTurboModule.pushStringToHarmony('pages/MusicPlay', 1);
}}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
},
geometryView: {
position: 'absolute',
width: 60,
height: 60,
backgroundColor: 'red',
},
});
export default PlayList;MusicPlay页面
function MusicPlay() {
return (
<SafeAreaView style={styles.container}>
<GeometryView style={{ width: 200, height: 200, backgroundColor: 'red' }} geometryViewID={'test'} onGeometryViewClick={() => {
SampleTurboModule.pushStringToHarmony('pop', 2)
}} >
</GeometryView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
},
text: {
fontSize: 18,
color: '#333',
},
});
export default MusicPlay;原生侧
PlayListPage监听RN页面跳转事件,如果事件触发,调用this.navPathStack.pushPath({ name: 'MusicPlayPage' }),跳转至原生MusicPlayPage页面。
@Component
export default struct PlayListPage {
private instance: RNInstance = LoadManager.instance;
private bundlePath = 'bundle/playlist.harmony.bundle'
private moduleName = 'PlayList'
@StorageLink('isMetroAvailable') isMetroAvailable: boolean = false
@Consume('navPathStack') navPathStack: NavPathStack
aboutToAppear() {
emitter.on({ eventId: 1 }, () => {
animateTo({duration: 700, curve: Curve.Friction}, () => {
this.navPathStack.pushPath({ name: 'MusicPlayPage' })
});
});
}
aboutToDisappear() {
emitter.off(1);
}
build() {
NavDestination() {
if (this.isMetroAvailable) {
MetroBaseRN({
moduleName: this.moduleName,
}).align(Alignment.Top).margin({ top: 0 })
} else if (this.instance) {
BaseRN({
rnInstance: this.instance,
moduleName: this.moduleName,
bundlePath: this.bundlePath,
}).align(Alignment.Top).margin({ top: 0 })
} else {
Text('加载失败')
}
}
.hideTitleBar(true)
}
}MusicPlayPage加载RN侧MusicPlay页面
@Component
export default struct MusicPlayPage {
private instance: RNInstance = LoadManager.instance
private bundlePath = 'bundle/musicplay.harmony.bundle'
private moduleName = 'MusicPlay'
@StorageLink('isMetroAvailable') isMetroAvailable: boolean = false
@Consume('navPathStack') navPathStack: NavPathStack
aboutToAppear() {
emitter.on({ eventId: 2 }, () => {
animateTo({duration: 700, curve: Curve.Friction}, () => {
this.navPathStack.pop()
});
});
}
aboutToDisappear() {
emitter.off(2);
}
build() {
NavDestination() {
if (this.isMetroAvailable) {
MetroBaseRN({
moduleName: this.moduleName,
})
.align(Alignment.Top).margin({ top: 20 })
} else if (this.instance) {
BaseRN({
rnInstance: this.instance,
moduleName: this.moduleName,
bundlePath: this.bundlePath,
}).align(Alignment.Top).margin({ top: 20 })
} else {
Text('加载失败')
}
}
.geometryTransition('test') // 设置同RN侧一致的id
.hideTitleBar(true)
}
}场景二:当前页面和目标页面均是RN页面
RN侧当前页面
使用了GeometryTransitionView组件,并设置了geometryViewID为'test',pageType设置为'current',点击跳转按钮调用原生navPathStack.pushPath,跳转至目标页面。
Tip: duration动画执行时间在当前页面设置不会生效,具体动画执行时间由目标页面的duration控制。
<View style={{ width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center' }}>
<GeometryTransitionView geometryViewID='test' style={{ width: 100, height: 100, backgroundColor: 'black' }} isFollow={false} duration={700} pageType={'current'}>
</GeometryTransitionView>
<Button title="跳转" onPress={() => { SampleTurboModule.pushStringToHarmony('pages/TargetPage', 1); }}></Button>
</View>原生侧当前页面
监听路由跳转事件,跳转至目标页面。
aboutToAppear() {
emitter.on({ eventId: 1 }, (eventData) => {
this.pagePathsGoods.pushPath({ name: "TargetPage" }, false);
});
}RN侧目标页面
使用了GeometryTransitionView组件,并设置了与 “当前页面“ 一致的geometryViewID:'test',pageType设置为'target',duration为设置从 “当前页面“ 跳转至目标页面的动画执行时间,点击返回按钮调用原生navPathStack.pop,返回 “当前页面“ 。
<View style={{ width: '100%', height: '50%', justifyContent: 'flex-end', alignItems: 'center', paddingBottom: '120' }}>
<GeometryTransitionView
style={{ width: 200, height: 200, backgroundColor: 'red' }}
geometryViewID={'test'}
isFollow={false}
duration={700}
pageType={'target'}
>
</GeometryTransitionView>
<Button title="返回" onPress={() => { SampleTurboModule.pushStringToHarmony('pages/CurrentPage', 2); }}></Button>
</View>原生侧目标页面
监听路由返回事件,使用动画返回跳转至 “当前页面“ 。
aboutToAppear() {
emitter.on({ eventId: 2 }, (eventData) => {
if (eventData.data) {
const path: string = eventData.data['param'];
if (path === "pages/CurrentPage") {
animateTo({ duration: 700 }, () => {
this.pagePathsGoods.pop(false);
})
}
}
});
}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", "@hadss/react_native_geometry_transition": "file:../../node_modules/@hadss/react_native_geometry_transition/harmony/geometry_transition.har", }b.配置CMakeLists和引入GeometryViewPackage:
打开
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 + add_subdirectory("${OH_MODULE_DIR}/@hadss/react_native_geometry_transition/src/main/cpp" ./geometry_transition) add_subdirectory("${RNOH_CPP_DIR}" ./rn) add_library(rnoh_app SHARED "./PackageProvider.cpp" "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" ) target_link_libraries(rnoh_app PUBLIC rnoh) + target_link_libraries(rnoh_app PUBLIC geometry_transition)c.打开
entry/src/main/cpp/PackageProvider.cpp,添加:#include "RNOH/PackageProvider.h" + #include "GeometryViewPackage.h" using namespace rnoh; std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) { return { + std::make_shared<GeometryViewPackage>(ctx) }; }d.运行:
点击右上角的
sync按钮或者在终端执行:
cd entry ohpm install然后编译、运行即可。
在 ArkTS 侧引入 GeometryTransitionView
... + import { GeometryTransitionView } from '@hadss/react_native_geometry_transition'; @Builder export function buildCustomRNComponent(ctx: ComponentBuilderContext) { ... + if (ctx.componentName === GeometryTransitionView.NAME) { + GeometryTransitionView({ + ctx: ctx.rnComponentContext, + tag: ctx.tag + }) + } ... } ...在
entry/src/main/ets/pages/index.ets或entry/src/main/ets/rn/LoadBundle.ets找到常量arkTsComponentNames在其数组里添加组件名const arkTsComponentNames: Array<string> = [ SampleView.NAME, GeneratedSampleView.NAME, PropsDisplayer.NAME, + GeometryTransitionView.NAME ];在 ArkTS 侧引入 GeometryTransitionViewPackage
... + import { GeometryTransitionViewPackage } from '@hadss/react_native_geometry_transition/ts'; export function createRNPackages(ctx: RNPackageContext): RNPackage[] { return [ new SamplePackage(ctx), + new GeometryTransitionViewPackage(ctx) ]; }
方法二:
直接链接源码
如需使用直接链接源码,请参考直接链接源码说明
API
说明: "Platform"列表示支持的平台,All表示支持所有平台。
GeometryView
| Name | Description | Type | Platform |
|---|---|---|---|
| geometryViewID | 共享元素ID. | string | OpenHarmony |
| onGeometryViewClick | 点击GeometryView回调. | callback | OpenHarmony |
GeometryTransitionView
| Name | Description | Type | Platform |
|---|---|---|---|
| geometryViewID | 用于设置绑定关系,id置空字符串清除绑定关系避免参与共享行为,id可更换重新建立绑定关系。同一个id只能有两个组件绑定且是in/out不同类型角色,不能多个组件绑定同一个id。 | string | OpenHarmony |
| isFollow | 组件内共享元素转场动画参数。true代表跟随做共享动画,false代表不跟随做共享动画,默认值:false。 | boolean? | OpenHarmony |
| duration | 动画执行时间,默认值:1000ms。 | number? | OpenHarmony |
| pageType | 页面标志。 | 'current' | 'target' | OpenHarmony |
约束与限制:仅限用于原生 Navigation 路由跳转场景。
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
7 months ago