ReactNative for Harmony 项目鸿蒙化三方库集成实战:@react-native-ohos/react-native-picker
选择器(Picker)是移动应用中非常常见的交互组件,用于让用户从预定义的选项列表中进行选择。是一个专为 React Native 跨平台应用(包括 HarmonyOS)设计的选择器库,它采用底部弹出式选择器,支持单列、多列、联动等多种选择场景。库名称版本信息4.3.10: 支持 RN 0.72 版本4.4.0: 支持 RN 0.77 版本官方仓库主要功能支持单列、多列、联动选择器丰富的自定义样式
📋 前言
选择器(Picker)是移动应用中非常常见的交互组件,用于让用户从预定义的选项列表中进行选择。@react-native-ohos/react-native-picker 是一个专为 React Native 跨平台应用(包括 HarmonyOS)设计的选择器库,它采用底部弹出式选择器,支持单列、多列、联动等多种选择场景。
🎯 库简介
基本信息
-
库名称:
@react-native-ohos/react-native-picker -
版本信息:
4.3.10: 支持 RN 0.72 版本4.4.0: 支持 RN 0.77 版本
-
官方仓库: https://github.com/react-native-oh-library/react-native-picker
-
主要功能:
- 支持单列、多列、联动选择器
- 丰富的自定义样式配置
- 兼容 Android、iOS 和 HarmonyOS 三端
-
兼容性验证:
- RNOH: 0.72.96; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112
- RNOH: 0.72.33; SDK: HarmonyOS NEXT B1; IDE: DevEco Studio: 5.0.3.900; ROM: Next.0.0.71
- RNOH: 0.77.18; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112
为什么需要这个库?
虽然各平台都有原生的选择器组件,但使用 @react-native-ohos/react-native-picker 有以下优势:
- 统一API: 在三端使用相同的API,降低开发成本
- 底部弹出模式: 提供统一的底部弹出式选择器体验
- 支持联动选择: 支持多级联动选择,如省市区选择
- HarmonyOS 支持: 专门为 HarmonyOS 平台适配
- 样式灵活: 支持丰富的自定义样式配置
📦 安装步骤
1. 使用 npm 安装
在项目根目录执行以下命令:
npm install @react-native-ohos/react-native-picker
2. 验证安装
安装完成后,检查 package.json 文件,应该能看到新增的依赖。根据您的 RN 版本选择对应的库版本:
{
"dependencies": {
"@react-native-ohos/react-native-picker": "4.4.0", // RN 0.77 版本
// 或
"@react-native-ohos/react-native-picker": "4.3.10", // RN 0.72 版本
// ... 其他依赖
}
}
我的安装后如下
"@react-native-ohos/react-native-picker": "^4.3.8-rc.1"
🔧 HarmonyOS 平台配置 ⭐
由于 HarmonyOS 暂不支持 AutoLink,需要手动配置原生端代码。本文采用方法二:直接链接源码的方式。
1 引入原生端代码
方法二:直接链接源码
目前 DevEco Studio 不支持通过源码引入外部 module,我们推荐使用直接链接源码的方式,将源码通过操作改成 harmony 工程的内部模块。
步骤 1: 把 <RN工程>/node_modules/@react-native-ohos/react-native-picker/harmony 目录下的源码 picker 复制到 harmony(鸿蒙壳工程)工程根目录下。

步骤 2: 在 harmony 工程根目录的 build-profile.template.json5(若存在)和 build-profile.json5 添加以下模块:
modules: [
...
{
name: '<xxx>',
srcPath: './<xxx>',
},
{
name: 'picker',
srcPath: './picker',
}
]

步骤 3: 打开 picker/oh-package.json5,修改 react-native-openharmony 和项目的版本一致。
步骤 4: 打开 entry/oh-package.json5,添加以下依赖:
"dependencies": {
"@rnoh/react-native-openharmony": "0.72.90",
"@react-native-ohos/react-native-picker": "file:../picker"
}

步骤 5: 点击 DevEco Studio 右上角的 sync 按钮
2 配置CMakeLists和导入PickerPackage
- 修改
entry/src/main/cpp/CMakeLists.txt
set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-picker/src/main/cpp" ./picker)
target_link_libraries(rnoh_app PUBLIC rnoh_native_picker)
- 修改
entry/src/main/cpp/PackageProvider.cpp
#include "PickerPackage.h"
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
return {
// ... 其他包
std::make_shared<PickerPackage>(ctx),
};
}
3 在ArkTs侧引入PickerViewPackage
修改 entry/src/main/ets/RNPackagesFactory.ts
import { PickerViewPackage } from '@react-native-ohos/react-native-picker/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
return [
// ... 其他包
new PickerViewPackage(ctx),
];
}
注意
把picker/ts.ts修改为picker/ts.ets否则在运行的时候会报错

💻 完整代码示例
下面是一个完整的示例,展示了 react-native-picker 的各种使用场景,包括单列选择、多列选择、联动选择等:
import React, { useState } from 'react';
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, SafeAreaView } from 'react-native';
import Picker from 'react-native-picker';
function PickerDemo() {
// 状态管理
const [selectedLanguage, setSelectedLanguage] = useState('JavaScript');
const [selectedColor, setSelectedColor] = useState('红色');
const [selectedCity, setSelectedCity] = useState('北京');
const [selectedDate, setSelectedDate] = useState('2024-01-01');
const [selectedSpec, setSelectedSpec] = useState({ color: '黑色', size: 'M', quantity: '1' });
// 1. 单列选择器 - 选择编程语言
const showLanguagePicker = () => {
Picker.init({
pickerData: ['Java', 'JavaScript', 'Python', 'C++', 'C#'],
selectedValue: [selectedLanguage],
pickerTitleText: '选择编程语言',
pickerConfirmBtnText: '确定',
pickerCancelBtnText: '取消',
onPickerConfirm: (pickedValue) => {
const value = Array.isArray(pickedValue) ? pickedValue[0] : pickedValue;
setSelectedLanguage(value);
},
});
Picker.show();
};
// 2. 单列选择器 - 自定义样式选择颜色
const showColorPicker = () => {
Picker.init({
pickerData: ['红色', '绿色', '蓝色', '黄色', '紫色'],
selectedValue: [selectedColor],
pickerTitleText: '选择颜色',
pickerConfirmBtnText: '确定',
pickerCancelBtnText: '取消',
// 自定义样式
pickerToolBarBg: [255, 255, 255, 1],
pickerBg: [255, 255, 255, 1],
pickerTitleColor: [0, 0, 0, 1],
pickerConfirmBtnColor: [0, 122, 255, 1],
pickerCancelBtnColor: [0, 0, 0, 1],
pickerFontColor: [0, 0, 0, 1],
pickerFontSize: 16,
onPickerConfirm: (pickedValue) => {
const value = Array.isArray(pickedValue) ? pickedValue[0] : pickedValue;
setSelectedColor(value);
},
});
Picker.show();
};
// 3. 单列选择器 - 城市选择
const showCityPicker = () => {
Picker.init({
pickerData: ['北京', '上海', '广州', '深圳', '杭州'],
selectedValue: [selectedCity],
pickerTitleText: '选择城市',
onPickerConfirm: (pickedValue) => {
const value = Array.isArray(pickedValue) ? pickedValue[0] : pickedValue;
setSelectedCity(value);
},
});
Picker.show();
};
// 4. 多列选择器 - 日期选择
const showDatePicker = () => {
const years = Array.from({ length: 100 }, (_, i) => `${2024 - i}年`);
const months = Array.from({ length: 12 }, (_, i) => `${i + 1}月`);
const days = Array.from({ length: 31 }, (_, i) => `${i + 1}日`);
Picker.init({
pickerData: [years, months, days],
selectedValue: ['2024年', '1月', '1日'],
pickerTitleText: '选择日期',
onPickerConfirm: (pickedValue) => {
const values = Array.isArray(pickedValue) ? pickedValue : [pickedValue];
const year = values[0] ? values[0].replace('年', '') : '2024';
const month = values[1] ? values[1].replace('月', '').padStart(2, '0') : '01';
const day = values[2] ? values[2].replace('日', '').padStart(2, '0') : '01';
setSelectedDate(`${year}-${month}-${day}`);
},
});
Picker.show();
};
// 5. 联动选择器 - 商品规格
const showSpecPicker = () => {
const colorData = ['黑色', '白色', '灰色', '蓝色'];
const sizeData = ['XS', 'S', 'M', 'L', 'XL', 'XXL'];
const quantityData = Array.from({ length: 10 }, (_, i) => `${i + 1}`);
Picker.init({
pickerData: [colorData, sizeData, quantityData],
selectedValue: [selectedSpec.color, selectedSpec.size, selectedSpec.quantity],
pickerTitleText: '选择商品规格',
onPickerConfirm: (pickedValue) => {
const values = Array.isArray(pickedValue) ? pickedValue : [pickedValue];
setSelectedSpec({
color: values[0] || selectedSpec.color,
size: values[1] || selectedSpec.size,
quantity: values[2] || selectedSpec.quantity,
});
},
});
Picker.show();
};
// 6. 高级联动选择器 - 省市区三级联动
const showAreaPicker = () => {
const data: Record<string, string[]> = {
北京市: ['东城区', '西城区', '朝阳区', '海淀区'],
上海市: ['黄浦区', '徐汇区', '长宁区', '静安区'],
广东省: ['广州市', '深圳市', '珠海市', '佛山市'],
};
const provinces = Object.keys(data);
const cities = data[provinces[0] as keyof typeof data];
Picker.init({
pickerData: [provinces, cities],
selectedValue: [provinces[0], cities[0]],
pickerTitleText: '选择省市区',
onPickerConfirm: (pickedValue) => {
console.log('选择结果:', pickedValue);
},
});
Picker.show();
};
// 颜色映射
const colorMap: Record<string, string> = {
'红色': '#FF0000',
'绿色': '#00FF00',
'蓝色': '#0000FF',
'黄色': '#FFFF00',
'紫色': '#800080',
};
return (
<SafeAreaView style={styles.container}>
<ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollContent}>
<Text style={styles.title}>Picker 选择器演示</Text>
{/* 1. 基础单列选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>1. 基础单列选择器</Text>
<Text style={styles.description}>选择编程语言,展示最基础的使用方式</Text>
<TouchableOpacity style={styles.button} onPress={showLanguagePicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<Text style={styles.result}>当前选择: {selectedLanguage}</Text>
</View>
{/* 2. 自定义样式选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>2. 自定义样式选择器</Text>
<Text style={styles.description}>自定义颜色、字体大小等样式配置</Text>
<TouchableOpacity style={styles.button} onPress={showColorPicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<View style={styles.colorPreviewContainer}>
<Text style={styles.result}>当前选择: {selectedColor}</Text>
<View style={[styles.colorPreview, { backgroundColor: colorMap[selectedColor] || '#000000' }]} />
</View>
</View>
{/* 3. 城市选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>3. 城市选择器</Text>
<Text style={styles.description}>选择城市,展示单列选择器的实际应用</Text>
<TouchableOpacity style={styles.button} onPress={showCityPicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<Text style={styles.result}>当前选择: {selectedCity}</Text>
</View>
{/* 4. 日期选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>4. 日期选择器</Text>
<Text style={styles.description}>使用多列选择器实现日期选择功能</Text>
<TouchableOpacity style={styles.button} onPress={showDatePicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<Text style={styles.result}>当前选择: {selectedDate}</Text>
</View>
{/* 5. 商品规格选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>5. 商品规格选择器</Text>
<Text style={styles.description}>使用多列选择器实现商品规格选择</Text>
<TouchableOpacity style={styles.button} onPress={showSpecPicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<Text style={styles.result}>
当前选择: {selectedSpec.color} / {selectedSpec.size} / 数量 {selectedSpec.quantity}
</Text>
</View>
{/* 6. 省市区联动选择器 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>6. 省市区联动选择器</Text>
<Text style={styles.description}>展示联动选择器的使用方式</Text>
<TouchableOpacity style={styles.button} onPress={showAreaPicker}>
<Text style={styles.buttonText}>打开选择器</Text>
</TouchableOpacity>
<Text style={styles.result}>选择结果请查看控制台</Text>
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
scrollView: {
flex: 1,
},
scrollContent: {
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
textAlign: 'center',
marginBottom: 30,
},
section: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
marginBottom: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#333',
marginBottom: 8,
},
description: {
fontSize: 14,
color: '#666',
marginBottom: 12,
},
button: {
backgroundColor: '#007AFF',
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
alignItems: 'center',
marginBottom: 12,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
result: {
fontSize: 14,
color: '#333',
fontWeight: '500',
},
colorPreviewContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
colorPreview: {
width: 40,
height: 40,
borderRadius: 8,
borderWidth: 1,
borderColor: '#ddd',
},
});
export default PickerDemo;

📖 代码讲解
1. 导入库
import Picker from 'react-native-picker';
说明: 使用 react-native-picker 库时,导入方式不变,仍然是 import Picker from 'react-native-picker'。
2. 单列选择器
使用场景: 选择编程语言、城市、颜色等单一维度的数据
关键配置:
pickerData: 数组形式的数据,如['Java', 'JavaScript', 'Python']selectedValue: 默认选中的值,需要是数组形式,如['JavaScript']onPickerConfirm: 确认选择时的回调,参数是选中的值数组
注意: 即使是单列选择器,selectedValue 和回调函数的参数也必须是数组形式,通过索引访问实际值:pickedValue[0]
3. 自定义样式配置
可配置的样式属性:
pickerToolBarBg: 工具栏背景色(RGBA 数组)pickerBg: 选择器背景色(RGBA 数组)pickerTitleColor: 标题文字颜色(RGBA 数组)pickerConfirmBtnColor: 确认按钮文字颜色(RGBA 数组)pickerCancelBtnColor: 取消按钮文字颜色(RGBA 数组)pickerFontColor: 选项文字颜色(RGBA 数组)pickerFontSize: 选项文字大小
颜色格式: 使用 RGBA 数组,如 [255, 255, 255, 1] 表示白色(R=255, G=255, B=255, A=1)
4. 多列选择器
使用场景: 日期选择、商品规格选择等需要多列的情况
关键配置:
pickerData: 数组的数组,如[years, months, days]selectedValue: 对应每列的默认值,如['2024年', '1月', '1日']onPickerConfirm: 回调参数是多列选中的值数组
数据处理: 在回调函数中,需要对每列的数据进行处理,如将 2024年 转换为 2024。
5. 联动选择器
使用场景: 省市区三级联动等需要根据前一列选择更新后一列的情况
实现方式:
- 构建嵌套的数据结构
- 在
onPickerSelect回调中动态更新后一列的数据(完整实现需要更多代码) - 示例中展示了基础的联动结构
6. 状态管理
推荐方式: 使用 useState 管理每个选择器的选中值
const [selectedLanguage, setSelectedLanguage] = useState('JavaScript');
注意事项:
- 状态值应该存储实际使用的值(如
'JavaScript'),而不是显示值(如'2024年') - 在
onPickerConfirm回调中更新状态 - 使用状态值显示选择结果
7. 显示和隐藏选择器
显示选择器:
Picker.show();
隐藏选择器:
Picker.hide();
切换显示状态:
Picker.toggle();
检查选择器状态:
const isShown = Picker.isPickerShow();
最佳实践: 通常在按钮的 onPress 事件中调用 Picker.show(),在 onPickerConfirm 和 onPickerCancel 回调中会自动隐藏选择器。
⚠️ 注意事项与最佳实践
1. Picker.init() 配置选项
常用配置:
pickerData: 选择器数据,数组或数组的数组selectedValue: 默认选中的值(数组形式)onPickerConfirm: 确认选择时的回调函数onPickerCancel: 取消选择时的回调函数pickerTitleText: 选择器标题
样式配置:
- 颜色值使用 RGBA 数组格式:
[R, G, B, A] - 每个颜色分量的范围是 0-255
- 透明度 A 的范围是 0-1
2. 数据格式要求
单列选择器:
pickerData: ['选项1', '选项2', '选项3']
selectedValue: ['选项1']
多列选择器:
pickerData: [['a1', 'a2'], ['b1', 'b2']]
selectedValue: ['a1', 'b1']
联动选择器:
pickerData: {
'选项1': ['子选项1-1', '子选项1-2'],
'选项2': ['子选项2-1', '子选项2-2']
}
3. 回调函数参数
重要: onPickerConfirm 回调函数的参数类型需要特别处理
onPickerConfirm: (pickedValue) => {
// pickedValue 可能是数组,也可能是单个值
const values = Array.isArray(pickedValue) ? pickedValue : [pickedValue];
console.log(values[0]); // 第一列的值
console.log(values[1]); // 第二列的值(如果有)
}
最佳实践: 始终使用 Array.isArray() 检查参数类型,确保代码的健壮性。
4. 性能优化
- 避免在渲染函数中重复调用
Picker.init() - 使用
useState管理选中值,避免不必要的重新渲染 - 对于大量数据,考虑分页或虚拟滚动
5. HarmonyOS 特殊处理
- 确保原生代码正确链接
- 在 HarmonyOS 设备上测试样式效果
- 注意不同设备的屏幕适配
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)