1.0.6 • Published 5 months ago

@hadss/react_native_geometry_transition v1.0.6

Weekly downloads
-
License
Apache-2.0
Repository
-
Last release
5 months ago

@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_transition

yarn

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"
  }
}

引入原生端代码

目前有两种方法:

方法一:

  1. 通过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

    然后编译、运行即可。

  2. 在 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.etsentry/src/main/ets/rn/LoadBundle.ets 找到常量 arkTsComponentNames 在其数组里添加组件名

    const arkTsComponentNames: Array<string> = [
      SampleView.NAME,
      GeneratedSampleView.NAME,
      PropsDisplayer.NAME,
    + GeometryTransitionView.NAME
      ];
  3. 在 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

NameDescriptionTypePlatform
geometryViewID共享元素ID.stringOpenHarmony
onGeometryViewClick点击GeometryView回调.callbackOpenHarmony

GeometryTransitionView

NameDescriptionTypePlatform
geometryViewID用于设置绑定关系,id置空字符串清除绑定关系避免参与共享行为,id可更换重新建立绑定关系。同一个id只能有两个组件绑定且是in/out不同类型角色,不能多个组件绑定同一个id。stringOpenHarmony
isFollow组件内共享元素转场动画参数。true代表跟随做共享动画,false代表不跟随做共享动画,默认值:false。boolean?OpenHarmony
duration动画执行时间,默认值:1000ms。number?OpenHarmony
pageType页面标志。'current' | 'target'OpenHarmony

约束与限制:仅限用于原生 Navigation 路由跳转场景。

1.0.6

5 months ago

1.0.5

5 months ago

1.0.4

5 months ago

1.0.3

5 months ago

1.0.2

5 months ago

1.0.2-rc.0

5 months ago

1.0.1

5 months ago

1.0.0

6 months ago

1.0.0-rc.0

7 months ago