@hxa-rn/react-native-photo-browser
v0.7.1
Published
Local and remote photo browser with captions, selections and grid view support for react native.
Readme
@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-browserWindows 下可在克隆时指定短目录名,例如 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-depsExample 从 npm 公仓安装 @hxa-rn/[email protected],不需要在仓根执行 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 Native0.72.5,RNOH@react-native-oh/react-native-harmony0.72.143 - HarmonyOS SDK:
compatibleSdkVersion5.1.0(18),targetSdkVersion6.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补useNativeDriverpropTypes.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 与本库版本
- 最小可复现代码或截图、日志
