ReactNative for OpenHarmony项目鸿蒙化三方库:@react-native-picker

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配


🚀 一、开篇引言

选择器(Picker)是移动应用中最基础且重要的交互组件之一,广泛应用于城市选择、日期设置、商品规格选择等场景。@react-native-picker/picker 是 React Native 官方推荐的选择器组件,提供跨平台一致的下拉选择体验。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用这个强大的选择器组件。

1.1 你将学到什么?

  • ✅ @react-native-picker/picker 的核心概念与工作原理
  • ✅ HarmonyOS 平台的完整集成流程
  • ✅ 单列选择器的实现与样式定制
  • ✅ Picker API 的深度解析
  • ✅ 实际应用场景的最佳实践

1.2 适用人群

  • 正在进行 React Native 鸿蒙化迁移的开发者
  • 需要实现选择器功能的应用开发者
  • 对跨平台 UI 组件开发感兴趣的技术爱好者

1.3 为什么选择 @react-native-picker/picker?

特点 说明
官方维护 React Native 社区官方推荐的 Picker 解决方案
跨平台一致 iOS、Android、HarmonyOS 表现一致
简洁易用 API 设计简洁,上手成本低
高度可定制 支持自定义样式、颜色、字体等
类型安全 完整的 TypeScript 类型支持

📦 二、库概览

2.1 基本信息

项目 内容
库名称 @react-native-ohos/picker
原库名称 @react-native-picker/picker
版本信息 2.6.4 (RN 0.72) / 2.11.2 (RN 0.77) / 2.11.4 (RN 0.82)
官方仓库 https://github.com/react-native-picker/picker
鸿蒙仓库 https://gitcode.com/openharmony-sig/rntpc_picker
开源协议 MIT

2.2 版本兼容性

三方库版本 支持RN版本 是否支持Autolink
2.11.4 0.82 No
2.11.2 0.77 No
2.6.4 0.72 Yes
<= 2.6.3@deprecated 0.72 No

2.3 核心能力矩阵

能力项 描述 HarmonyOS 支持
单列选择器 基础下拉选择 ✅ 完全支持
选中值控制 selectedValue 属性 ✅ 完全支持
值变化监听 onValueChange 回调 ✅ 完全支持
禁用状态 enabled 属性 ✅ 完全支持
自定义样式 style 属性 ✅ 完全支持
选中颜色 selectionColor 属性 ✅ 完全支持
选项颜色 Picker.Item color 属性 ❌ 不支持
选项字体 Picker.Item fontFamily ❌ 不支持
多行文本 numberOfLines 属性 ❌ 不支持

2.4 技术架构图

原生平台层
Bridge Layer
React Native 应用层
Picker Component
Native Module
PickerPackage
PickerManager
Android

android.widget.Spinner
iOS

UIPickerView
HarmonyOS

Picker组件

⚡ 三、快速开始

3.1 环境要求

依赖项 版本要求
React Native 0.72.x / 0.77.x
RNOH (鸿蒙框架) 0.72.90 / 0.77.18
HarmonyOS SDK 6.0.0.47+ (API 20)
DevEco Studio 5.0.3+ / 6.0+
Node.js 16.18.0+ / 18.x

3.2 一键安装

创建鸿蒙项目的过程不再进行描述,不懂得看这篇:https://blog.csdn.net/u011178696/article/details/151932277

bash 复制代码
npm install @react-native-ohos/picker@2.6.4-rc.1

或使用 yarn:

bash 复制代码
yarn add @react-native-ohos/picker@2.6.4-rc.1

3.3 验证安装

安装完成后,检查 package.json 文件:

json 复制代码
{
  "dependencies": {
    "@react-native-ohos/picker": "^2.6.4-rc.1"
  }
}

🔧 四、HarmonyOS 平台配置

步骤 1:配置 oh-package.json5(根据自己的版本来)
json 复制代码
{
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}
步骤 2:引入 HAR 包
json 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-ohos/picker": "file:../../node_modules/@react-native-ohos/picker/harmony/picker.har"
}
步骤 3:配置 CMakeLists.txt
diff 复制代码
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")

+ add_subdirectory("${OH_MODULES}/@react-native-ohos/picker/src/main/cpp" ./picker)

+ target_link_libraries(rnoh_app PUBLIC rnoh_picker)
步骤 4:配置 PackageProvider.cpp
diff 复制代码
+ #include "PickerPackage.h"

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
+     std::make_shared<PickerPackage>(ctx)
    };
}
步骤 5:在 ArkTS 侧引入组件
diff 复制代码
+ import { RNCPicker, PICKER_TYPE } from "@react-native-ohos/picker"

@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
+ if (ctx.componentName === PICKER_TYPE) {
+   RNCPicker({
+     ctx: ctx.rnComponentContext,
+     tag: ctx.tag
+   })
+ }
}

const arkTsComponentNames: Array<string> = [
+ PICKER_TYPE
];
步骤 6:引入 RNCPickerPackage
diff 复制代码
+ import { RNCPickerPackage } from '@react-native-ohos/picker/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
+   new RNCPickerPackage(ctx)
  ];
}

我在适配的时候,有个index.ets中给我导出ets,如下

不知道什么情况,我手动把.ets删掉了

📱 五、基础使用

5.1 简单选择器

最基础的选择器使用方式:

ts 复制代码
import { Picker } from '@react-native-ohos/picker';

const [selectedValue, setSelectedValue] = useState('java');

<Picker
  selectedValue={selectedValue}
  onValueChange={(itemValue, itemIndex) => setSelectedValue(itemValue)}
>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="JavaScript" value="js" />
  <Picker.Item label="Python" value="python" />
</Picker>

5.2 禁用状态选择器

tsx 复制代码
const [enabled, setEnabled] = useState(true);

<Picker
  selectedValue={selectedValue}
  onValueChange={(value) => setSelectedValue(value)}
  enabled={enabled}
>
  <Picker.Item label="选项一" value="option1" />
  <Picker.Item label="选项二" value="option2" />
</Picker>

5.3 动态渲染选项

tsx 复制代码
const cities = [
  { label: '北京', value: 'beijing' },
  { label: '上海', value: 'shanghai' },
  { label: '广州', value: 'guangzhou' },
];

<Picker
  selectedValue={selectedCity}
  onValueChange={(value) => setSelectedCity(value)}
>
  {cities.map((city) => (
    <Picker.Item key={city.value} label={city.label} value={city.value} />
  ))}
</Picker>

🎨 六、进阶用法

6.1 联动选择器

当主分类变化时,自动更新子分类选项:

ts 复制代码
const categories = {
  tech: [
    { label: '人工智能', value: 'ai' },
    { label: '区块链', value: 'blockchain' },
  ],
  entertainment: [
    { label: '电影', value: 'movie' },
    { label: '音乐', value: 'music' },
  ],
};

const [mainCategory, setMainCategory] = useState('tech');
const [subCategory, setSubCategory] = useState('ai');

const handleMainCategoryChange = (value: string) => {
  setMainCategory(value);
  setSubCategory(categories[value][0].value);
};

<Picker
  selectedValue={mainCategory}
  onValueChange={handleMainCategoryChange}
>
  <Picker.Item label="科技" value="tech" />
  <Picker.Item label="娱乐" value="entertainment" />
</Picker>

<Picker
  selectedValue={subCategory}
  onValueChange={setSubCategory}
>
  {categories[mainCategory].map((item) => (
    <Picker.Item key={item.value} label={item.label} value={item.value} />
  ))}
</Picker>

6.2 带图标的选项

tsx 复制代码
const languages = [
  { label: 'Java', value: 'java', icon: '☕' },
  { label: 'JavaScript', value: 'js', icon: '💛' },
  { label: 'Python', value: 'python', icon: '🐍' },
];

<Picker
  selectedValue={selectedLanguage}
  onValueChange={setSelectedLanguage}
>
  {languages.map((lang) => (
    <Picker.Item
      key={lang.value}
      label={`${lang.icon} ${lang.label}`}
      value={lang.value}
    />
  ))}
</Picker>

📚 七、API 详解

7.1 Picker Props

selectedValue

当前选中的值,用于控制选择器的选中状态。

tsx 复制代码
const [value, setValue] = useState('java');

<Picker selectedValue={value} onValueChange={setValue}>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python" value="python" />
</Picker>
onValueChange

选中项变化时的回调函数,接收两个参数:itemValueitemIndex

tsx 复制代码
<Picker
  selectedValue={value}
  onValueChange={(itemValue, itemIndex) => {
    console.log('选中值:', itemValue);
    console.log('选中索引:', itemIndex);
    setValue(itemValue);
  }}
>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python" value="python" />
</Picker>
style

选择器容器的样式,可设置高度、宽度、颜色等。

tsx 复制代码
<Picker
  selectedValue={value}
  onValueChange={setValue}
  style={{ height: 50, width: 200, backgroundColor: '#f0f0f0' }}
>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python" value="python" />
</Picker>
enabled

是否启用选择器,设置为 false 时选择器不可交互。

tsx 复制代码
<Picker
  selectedValue={value}
  onValueChange={setValue}
  enabled={false}
>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python" value="python" />
</Picker>
selectionColor

选中指示器的颜色(仅 iOS 和 HarmonyOS 支持)。

tsx 复制代码
<Picker
  selectedValue={value}
  onValueChange={setValue}
  selectionColor="#00d4ff"
>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python" value="python" />
</Picker>

7.2 Picker.Item Props

label

选项显示的文本内容。

tsx 复制代码
<Picker.Item label="Java 编程语言" value="java" />
value

选项的值,可以是字符串或数字。

tsx 复制代码
<Picker.Item label="Java" value="java" />
<Picker.Item label="版本号" value={18} />
enabled

是否启用该选项,设置为 false 时选项不可选。

tsx 复制代码
<Picker selectedValue={value} onValueChange={setValue}>
  <Picker.Item label="Java" value="java" />
  <Picker.Item label="Python (暂不可用)" value="python" enabled={false} />
</Picker>
color

选项的颜色(HarmonyOS 不支持)。

tsx 复制代码
<Picker.Item label="Java" value="java" color="#ff0000" />

7.3 静态方法

blur

以编程方式关闭选择器(仅 Android 支持)。

tsx 复制代码
const pickerRef = useRef(null);

<Picker ref={pickerRef} selectedValue={value} onValueChange={setValue}>
  <Picker.Item label="Java" value="java" />
</Picker>

<Button title="关闭选择器" onPress={() => pickerRef.current?.blur()} />
focus

以编程方式打开选择器(仅 Android 支持)。

tsx 复制代码
const pickerRef = useRef(null);

<Picker ref={pickerRef} selectedValue={value} onValueChange={setValue}>
  <Picker.Item label="Java" value="java" />
</Picker>

<Button title="打开选择器" onPress={() => pickerRef.current?.focus()} />

⚠️ 八、注意事项与常见问题

8.1 遗留问题

问题 说明
numberOfLines 属性不支持 HarmonyOS 的 Picker 组件不支持多行文本
Picker.Item 的 color 和 fontFamily 不支持 OH 的 Picker 组件不支持单独设置选项样式
themeVariant 属性不支持 主题变体功能暂未适配
itemStyle 不支持设置 textAlign OH 的 Picker 不支持文本对齐设置

8.2 常见问题

Q1: 选择器高度设置不生效?

A: 确保使用 height 属性设置高度,而不是 minHeightmaxHeight

Q2: 如何实现多列选择器?

A: @react-native-picker/picker 是单列选择器,如需多列选择,请使用 @react-native-ohos/react-native-picker

Q3: 选择器样式无法自定义?

A: 部分样式属性在 HarmonyOS 上不支持,请参考核心能力矩阵。


💻 九、完整示例代码

精美选择器示例

ts 复制代码
import React, { useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  SafeAreaView,
} from 'react-native';
import { Picker } from '@react-native-ohos/picker';

const languages = [
  { label: 'Java', value: 'java', icon: '☕' },
  { label: 'JavaScript', value: 'js', icon: '💛' },
  { label: 'Python', value: 'python', icon: '🐍' },
  { label: 'TypeScript', value: 'ts', icon: '💙' },
  { label: 'Go', value: 'go', icon: '🐹' },
  { label: 'Rust', value: 'rust', icon: '🦀' },
  { label: 'Swift', value: 'swift', icon: '🍎' },
  { label: 'Kotlin', value: 'kotlin', icon: '🤖' },
];

const themes = [
  { label: '深色模式', value: 'dark' },
  { label: '浅色模式', value: 'light' },
  { label: '跟随系统', value: 'auto' },
];

export default function App() {
  const [selectedLanguage, setSelectedLanguage] = useState('js');
  const [selectedTheme, setSelectedTheme] = useState('light');

  const getLanguageInfo = (value: string) => {
    return languages.find((lang) => lang.value === value);
  };

  return (
    <SafeAreaView style={styles.container}>
      <ScrollView showsVerticalScrollIndicator={false}>
        <View style={styles.header}>
          <Text style={styles.headerTitle}>选择器演示</Text>
          <Text style={styles.headerSubtitle}>@react-native-picker/picker</Text>
        </View>

        <View style={styles.card}>
          <Text style={styles.cardTitle}>当前选择</Text>
          <View style={styles.selectedInfo}>
            <Text style={styles.selectedIcon}>
              {getLanguageInfo(selectedLanguage)?.icon}
            </Text>
            <Text style={styles.selectedName}>
              {getLanguageInfo(selectedLanguage)?.label}
            </Text>
          </View>
          <Text style={styles.selectedValue}>值: {selectedLanguage}</Text>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>编程语言选择</Text>
          <View style={styles.pickerWrapper}>
            <Picker
              selectedValue={selectedLanguage}
              onValueChange={(value) => setSelectedLanguage(value)}
              style={styles.picker}
              selectionColor="#00d4ff"
            >
              {languages.map((lang) => (
                <Picker.Item
                  key={lang.value}
                  label={lang.label}
                  value={lang.value}
                />
              ))}
            </Picker>
          </View>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>主题设置</Text>
          <View style={styles.pickerWrapper}>
            <Picker
              selectedValue={selectedTheme}
              onValueChange={(value) => setSelectedTheme(value)}
              style={styles.picker}
              selectionColor="#00d4ff"
            >
              {themes.map((theme) => (
                <Picker.Item key={theme.value} label={theme.label} value={theme.value} />
              ))}
            </Picker>
          </View>
        </View>

        <View style={styles.infoCard}>
          <Text style={styles.infoTitle}>组件信息</Text>
          <View style={styles.infoRow}>
            <Text style={styles.infoLabel}>库名称</Text>
            <Text style={styles.infoValue}>@react-native-ohos/picker</Text>
          </View>
          <View style={styles.infoRow}>
            <Text style={styles.infoLabel}>支持平台</Text>
            <Text style={styles.infoValue}>iOS / Android / HarmonyOS</Text>
          </View>
          <View style={styles.infoRow}>
            <Text style={styles.infoLabel}>组件类型</Text>
            <Text style={styles.infoValue}>单列滚动选择器</Text>
          </View>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#1a1a2e',
  },
  header: {
    padding: 24,
    backgroundColor: '#16213e',
    borderBottomLeftRadius: 24,
    borderBottomRightRadius: 24,
  },
  headerTitle: {
    fontSize: 28,
    fontWeight: 'bold',
    color: '#fff',
    textAlign: 'center',
  },
  headerSubtitle: {
    fontSize: 14,
    color: '#888',
    textAlign: 'center',
    marginTop: 5,
  },
  card: {
    margin: 16,
    padding: 24,
    backgroundColor: '#16213e',
    borderRadius: 16,
    alignItems: 'center',
  },
  cardTitle: {
    fontSize: 14,
    color: '#666',
    marginBottom: 12,
  },
  selectedInfo: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 8,
  },
  selectedIcon: {
    fontSize: 36,
    marginRight: 12,
  },
  selectedName: {
    fontSize: 32,
    fontWeight: 'bold',
    color: '#00d4ff',
  },
  selectedValue: {
    fontSize: 14,
    color: '#666',
    marginTop: 8,
  },
  section: {
    margin: 16,
    marginTop: 0,
    backgroundColor: '#16213e',
    borderRadius: 16,
    padding: 16,
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#fff',
    marginBottom: 12,
  },
  pickerWrapper: {
    backgroundColor: '#0f0f1a',
    borderRadius: 12,
    borderWidth: 1,
    borderColor: '#333',
    overflow: 'hidden',
  },
  picker: {
    height: 200,
    width: '100%',
    color: '#fff',
  },
  infoCard: {
    margin: 16,
    marginTop: 0,
    backgroundColor: '#16213e',
    borderRadius: 16,
    padding: 16,
    marginBottom: 32,
  },
  infoTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#fff',
    marginBottom: 16,
  },
  infoRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    paddingVertical: 10,
    borderBottomWidth: 1,
    borderBottomColor: '#252540',
  },
  infoLabel: {
    fontSize: 14,
    color: '#888',
  },
  infoValue: {
    fontSize: 14,
    color: '#00d4ff',
    fontWeight: '500',
  },
});

🔗 十、相关资源


📝 十一、总结

本文详细介绍了 @react-native-picker/picker 在 HarmonyOS 平台的使用方法。通过 Picker 组件,你可以轻松实现单列下拉选择功能,支持选中值控制、禁用状态、样式定制等特性。

核心要点

  • ✅ 支持单列下拉选择
  • ✅ 支持选中值控制和变化监听
  • ✅ 支持禁用状态设置
  • ✅ 跨平台一致的 API 设计
  • ✅ 支持 TypeScript 类型

适用场景

  • 语言/主题选择
  • 城市选择
  • 分类筛选
  • 设置选项

希望本文能帮助你在 HarmonyOS 项目中顺利集成选择器组件!

相关推荐
Swift社区1 小时前
鸿蒙 App 架构中的“领域拆分”
华为·架构·harmonyos
江南十四行4 小时前
ReAct Agent 基本理论与项目实战(一)
前端·react.js·前端框架
maaath4 小时前
【maaath】Flutter for OpenHarmony 手表配饰应用实战开发
flutter·华为·harmonyos
maaath5 小时前
【maaath】Flutter for OpenHarmony 跨平台计算器应用开发实践
flutter·华为·harmonyos
谢尔登7 小时前
10_从 React Hooks 本质看 useState
前端·ubuntu·react.js
辰同学ovo7 小时前
从全局登录状态管理学习 Redux
前端·javascript·学习·react.js
光影少年8 小时前
reeact虚拟DOM、Diff算法原理、key的作用与为什么不能用index
前端·react.js·掘金·金石计划
江南十四行8 小时前
ReAct Agent 基本理论与项目实战(二)
前端·react.js·前端框架
摘星编程9 小时前
当AI开始学会“使用工具“——从ReAct到MCP,大模型如何获得真正的行动力
前端·人工智能·react.js
前端不太难9 小时前
鸿蒙PC和App:都在走向 System
华为·状态模式·harmonyos