react-native-photo-browser:基于 React Native 鸿蒙生态的图片浏览组件项目

全屏图片浏览与选择组件

Branch3Tags2
FilesLast commitLast update
10 years ago
18 days ago
18 days ago
1 month ago
1 month ago
1 month ago
28 days ago
19 days ago
18 days ago
18 days ago
1 month ago
18 days ago
1 month ago

@hxa-rn/react-native-photo-browser

本项目基于 react-native-photo-browser 开发。如果在使用过程中有任何问题,欢迎在 GitCode 提交 Issue,会及时跟进。

项目介绍

@hxa-rn/react-native-photo-browser 是 react-native-photo-browser(上游版本 0.7.0)的鸿蒙(OpenHarmony / HarmonyOS,RNOH)适配包,当前版本 0.7.0(与上游版本号一致)。

上游是一个 React Native 图片浏览组件,支持全屏图片浏览、九宫格缩略图浏览、图片翻页、标题说明、图片选择、返回按钮、动作按钮和长按回调。

本包是纯 JS 组件库:不含 ETS / C++ 原生代码,不随包提供 HAR,不参与 Autolink,也不需要 Manual Link。

鸿蒙适配包版本 上游版本 React Native / RNOH 编译 SDK 接入方式
0.7.0 0.7.0 RN >=0.72(基于 0.72.5 + @react-native-oh/react-native-harmony 0.72.143) compatibleSdkVersion 5.1.0(18),targetSdkVersion 6.1.1(24) 纯 JS,npm install 后重新生成 JS Bundle 即可,无原生接入步骤

集成指南

1. 安装

在 RN 工程根目录执行:

npm install @hxa-rn/react-native-photo-browser --legacy-peer-deps

务必带 --legacy-peer-deps:运行依赖 @react-native-oh-tpl/react-native-progress 声明了原生 peer @react-native-oh-tpl/react-native-svg(只有它的 Circle / CircleSnail / Pie 需要)。本包只引用纯 JS 的 @react-native-oh-tpl/react-native-progress/Bar,从不引用 svg;不带该参数时 npm 7+ 会自动装入这个原生包,给宿主平添一条无用的 autolinking / HAR 链路。

运行时依赖(随本包自动安装):

依赖 版本 说明
@react-native-oh-tpl/react-native-progress ~5.0.1-0.0.3 鸿蒙化进度条,仅深引用纯 JS 的 Bar(全屏加载进度)
react-native-iphone-x-helper ^1.2.1 纯 JS;鸿蒙上恒取非刘海屏分支,行为与 Android 一致
prop-types 15.5.10 纯 JS

宿主需自备 react、react-native 与 RNOH(@react-native-oh/react-native-harmony),本包以 peerDependencies 声明前两者。

2. JS 侧导入

业务代码可以继续沿用上游包名:

import PhotoBrowser from 'react-native-photo-browser';

本包 package.json 声明了 "harmony": { "alias": "react-native-photo-browser" },RNOH 的 createHarmonyMetroConfig 会把上游包名解析到本包,无需改写 import。宿主 metro.config.js 使用 RNOH 模板的标准写法即可:

const {mergeConfig, getDefaultConfig} = require('@react-native/metro-config');
const {createHarmonyMetroConfig} = require('@react-native-oh/react-native-harmony/metro.config');

module.exports = mergeConfig(getDefaultConfig(__dirname), createHarmonyMetroConfig({
  reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony',
}));

也可以直接使用本包名导入:

import PhotoBrowser from '@hxa-rn/react-native-photo-browser';

本包不随包提供 TypeScript 类型声明。TypeScript 工程在任意被 tsconfig.json 收录的 .d.ts 文件中加一行模块声明,避免 TS7016(按实际使用的导入名二选一或都写):

declare module 'react-native-photo-browser';
declare module '@hxa-rn/react-native-photo-browser';

3. 鸿蒙原生侧

本包没有原生实现,因此不需要:在 oh-package.json5 / entry/oh-package.json5 中添加依赖、修改 CMakeLists.txt、在 PackageProvider.cpp 或 RNPackagesFactory.ets 中注册 Package。

安装后在 RN 工程根目录重新生成鸿蒙侧 JS Bundle 即可生效:

react-native bundle-harmony --dev false

默认写入 ./harmony/entry/src/main/resources/rawfile/bundle.harmony.js,本包的图片资源写入同级 assets/ 目录;鸿蒙工程不在 ./harmony 时,用 --bundle-output / --assets-dest 指定。随后用 DevEco Studio 编译运行宿主工程。

使用说明

基础用法

import React from 'react';
import PhotoBrowser from 'react-native-photo-browser';

const mediaList = [
  {
    photo: 'https://example.com/photo-1.jpg',
    thumb: 'https://example.com/thumb-1.jpg',
    caption: 'Photo 1',
    selected: false,
  },
  {
    photo: 'https://example.com/photo-2.jpg',
    thumb: 'https://example.com/thumb-2.jpg',
    caption: 'Photo 2',
    selected: true,
  },
];

export default function Gallery() {
  return (
    <PhotoBrowser
      mediaList={mediaList}
      initialIndex={0}
      enableGrid
      startOnGrid={false}
      displaySelectionButtons
      displayNavArrows
      displayActionButton
      alwaysDisplayStatusBar
      itemPerRow={3}
      onSelectionChanged={(media, index, isSelected) => {
        console.log('selection', media, index, isSelected);
      }}
      onActionButton={(media, index) => {
        console.log('action', media, index);
      }}
      onBack={() => {
        console.log('back');
      }}
    />
  );
}

常用场景

场景 配置方式
默认全屏浏览 传入 mediaList,保持 startOnGrid={false}
默认九宫格浏览 传入 startOnGrid={true}
显示选择按钮 传入 displaySelectionButtons={true} 并监听 onSelectionChanged
显示左右导航箭头 传入 displayNavArrows={true}
显示动作按钮 传入 displayActionButton={true} 并监听 onActionButton
自定义网格列数 传入 itemPerRow
控件常显 传入 alwaysShowControls={true}

接口文档

PhotoBrowser 属性

属性 类型 默认值 说明 HarmonyOS 支持
mediaList Array<Media>(必填) [] 图片媒体列表 是
style ViewStyle 无 容器样式 是
initialIndex number 0 全屏浏览初始图片索引 是
square boolean false 九宫格缩略图是否使用正方形 是
gridOffset number 0 从九宫格可用宽度中扣除的偏移量 是
itemPerRow number 3 九宫格每行缩略图数量 是
alwaysShowControls boolean false 顶栏、底栏和控制按钮是否常显 是
displayActionButton boolean false 是否显示动作按钮 是
displayNavArrows boolean false 是否显示左右导航箭头 是
alwaysDisplayStatusBar boolean false 控件隐藏时是否保持系统状态栏可见 是(见约束与限制)
enableGrid boolean true 是否启用九宫格入口 是
startOnGrid boolean false 是否默认从九宫格视图启动 是
displaySelectionButtons boolean false 是否显示图片选择按钮 是
displayTopBar boolean true 是否显示顶部栏 是
useCircleProgress boolean false 请求使用圆形加载进度 部分:降级为条形进度
delayPhotoLongPress number 1000 图片长按触发时长,单位 ms 是
customBottomBarButton React.ReactElement 无 在底栏动作按钮左侧插入的自定义按钮 是
customTitle (index, total) => string 无 全屏模式的标题,index 从 1 起;未传入时为 "<index> of <total>" 是
onSelectionChanged (media, index, isSelected) => void 空函数 图片选择状态变化回调 是
onActionButton (media, index) => void 无 动作按钮点击回调 是
onBack () => void 无 返回按钮点击回调(实际会收到按压事件,可忽略);未传入时不显示返回按钮 是
onPhotoLongPress (media, index) => void 空函数 图片长按回调 是

另有上游代码支持、但上游文档未列出的 topBarComponent / bottomBarComponent(替换顶栏 / 底栏组件),行为与上游一致。

Media

字段 类型 是否必填 说明
photo string / 图片资源 是 大图,远程 URI 或 require() 得到的 RN 图片资源
thumb string / 图片资源 否 缩略图,缺省时回落使用 photo
caption string 否 图片说明文字
selected boolean 否 初始选中状态
id string / number 否 媒体唯一标识,列表 key 优先使用它

回调说明

回调 触发时机 参数
onSelectionChanged 用户点击选择按钮后 当前媒体对象、索引、选中状态
onActionButton 用户点击动作按钮后 当前媒体对象、索引
onBack 用户点击返回按钮后 无
onPhotoLongPress 用户长按当前图片后 当前媒体对象、索引

快速验证(运行 Example)

前置条件

依赖 版本要求
Node.js >= 20(示例工程 engines 要求);DevEco Sync 时 preInstall 钩子也要用 PATH 中的 Node.js 20+,新装 Node.js 后需重启 DevEco Studio
DevEco Studio 6.1.1(本版本验证所用)
HarmonyOS SDK API 18+(example/harmony 的 compatibleSdkVersion 为 5.1.0(18))
路径 Windows 下仓库根目录的完整路径不超过 40 个字符,否则原生构建的中间文件路径会超过系统上限

运行步骤

1. 克隆仓库

git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-photo-browser.git
cd react-native-photo-browser

Windows 下可在克隆时指定短目录名,例如 git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-photo-browser.git C:\rpb。

2. 进入 example 目录,安装依赖

cd example
npm install --legacy-peer-deps

Example 从 npm 公仓安装 @hxa-rn/react-native-photo-browser@0.7.1,不需要在仓根执行 npm pack。

3. 生成 JS Bundle

npm run dev

产物:harmony/entry/src/main/resources/rawfile/bundle.harmony.js

4. 用 DevEco Studio 打开鸿蒙工程

  • 打开 DevEco Studio,选择 example/harmony 目录
  • 首次构建请在 File → Project Structure → Signing Configs 勾选 Automatically generate signature,Apply 后 Sync
  • 等待 Sync 完成

5. 编译并运行 HAP

在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备。

example_auto(自动化用例工程)步骤相同,把 example 换成 example_auto 即可,两者的依赖与构建输出相互独立。

注意:本包为纯 JS,Example 无原生接入步骤,Metro alias 已预置。编 HAP 前必须先执行 npm run dev;改过 JS 后重新执行再运行。两个示例的应用包名均为 com.example.react_native_photo_browser;示例图片来自网络(picsum.photos),设备需可联网。

约束与限制

兼容性

  • React 18.2.0,React Native 0.72.5,RNOH @react-native-oh/react-native-harmony 0.72.143
  • HarmonyOS SDK:compatibleSdkVersion 5.1.0(18),targetSdkVersion 6.1.1(24)

以上为本版本编译验证所用的环境(DevEco Studio 6.1.1),不代表其他 RNOH / SDK 版本不可用,但未经验证。

验证状态

  • 0.7.0:版本号改为与上游版本一致,代码与 1.0.1 相同。版本号低于此前发布的 1.0.x,^1.0.0 之类的范围不会解析到本版本,请按精确版本安装。发布前以候选包为依赖,example 与 example_auto 在上述环境中 assembleHap 编译通过;未做真机验证。
  • 1.0.1:全屏模式右上角选择按钮的位置恢复为上游取值(fullScreenSelectionIcon 的 top 由 112 改回 142;1.0.0 曾为适配示例安全区改小),其余代码与 1.0.0 相同。发布前以候选包为依赖,example 与 example_auto 在上述环境中 assembleHap 编译通过;未做真机验证。
  • 1.0.0:在 0.0.1-beta 基础上修复「从九宫格点缩略图回到全屏时,大图偶发以错误尺寸显示(近乎不可见),翻页后恢复」的问题(全屏列表随视口变化重渲染),并让全屏标题在首帧即正确显示。本版本发布前未单独做编译或真机验证。
  • 0.0.1-beta:以源码仓库的 example 与 example_auto 两个示例工程为宿主,从 npm 安装本包,在上述环境中 assembleHap 编译通过;真机(HarmonyOS API 26)冒烟通过了全屏浏览、翻页、九宫格与返回,并发现了上述已在 1.0.0 修复的问题。
  • 尚未完成:功能黑盒用例集(28 例)尚未在 1.0.0、1.0.1、0.7.0 上重跑。

与 Android / iOS 的行为差异

# 差异 说明 影响
1 全屏加载进度恒为条形 上游 Android 显示系统转圈(ActivityIndicator),iOS 可用 useCircleProgress 切到圆环;圆环依赖原生 svg,本包不引入,鸿蒙侧恒为条形进度 视觉差异,功能不受影响
2 加载进度随框架实现而异 RNOH 0.72.143 C-API 支持 Image.onProgress 的字节进度;无此回调的实现下从加载态直接完成 大图按真实回调更新进度,缓存命中可能直接完成;缩略图不展示增量进度
3 状态栏作用于整个窗口 鸿蒙的状态栏设置作用于整个应用窗口,translucent 为空操作;本组件默认在切换控件显隐时同步隐藏 / 显示状态栏 建议传 alwaysDisplayStatusBar={true};若宿主其他页面对状态栏样式敏感,离开 PhotoBrowser 后自行重设
4 返回按钮无文字 与 Android 一致只显示箭头图标 视觉差异
5 EXIF 旋转元数据 RNOH 的 orientation=auto 依赖 ArkUI NODE_IMAGE_ORIENTATION,仅 API 21+ 支持;更低 API 的设备上带旋转信息的图片按原始方向显示 建议设备 API 21+,或业务侧预先旋正图片

相对上游的主要库内改动

  • FullScreenContainer:补 componentWillUnmount,移除 didUpdateDimensions 监听并清理懒加载重试定时器(上游监听器从不移除,会对已卸载组件 forceUpdate)
  • FullScreenContainer:越界的 initialIndex 钳制到有效范围(上游首帧会因读取不存在的图片而崩溃)
  • index.js:字符串 ref 改为 React.createRef()(React 18 已废弃字符串 ref)
  • index.js / bar/BarContainer.js:Animated.timing 补 useNativeDriver
  • propTypes.js:以 stylePropType 替代 ViewPropTypes.style(RNOH 的 react-native-harmony 导出表无 ViewPropTypes,0.72.101 核实;直接引用会导致整库加载即崩)
  • GridContainer:numColumns 跟随 itemPerRow(上游写死 3 列)

其他约束

  • 本库不主动申请系统权限;远程图片访问(网络)、相册读取等权限由业务应用按自身场景声明。
  • 本库不内置系统分享、复制或保存到相册能力,业务侧可在 onActionButton 中自行实现。
  • 九宫格重排依赖应用窗口实际尺寸变化;应用未开启转屏时不会触发布局重排。

开源license

本项目基于 MIT License 开源,与上游 react-native-photo-browser 一致,详见包内 LICENSE。

问题反馈渠道

使用过程中发现问题,请在 GitCode Issues 提交,并附上:

  • 问题现象和复现步骤
  • 设备型号、系统版本和 API 档位
  • React Native、RNOH 与本库版本
  • 最小可复现代码或截图、日志

Introduction

全屏图片浏览与选择组件

Customize your domain