目录
一、简介
官方案例
主要特点
二、基础用法
安装
简单示例
WheelPicker 组件属性
三、代码注释与实际效果展示(便于理解)
便于理解的代码(含注释)
效果展示
* 四、官方给出的其他扩展性功能
触觉反馈功能
扩展API
钩子函数
高阶组件
额外属性
五、原创项目效果展示
一、简介
React Native Wheel Picker 是一个为 iOS 和 Android 平台设计的灵活选择器组件,采用 MIT 开源协议发布。它完全基于 JavaScript 实现,不需要原生代码支持。 官方文档
官方案例
主要特点
-
纯 JavaScript 实现(无需原生代码)、统一的 API 接口、使用原生动画效果、支持触觉反馈、支持虚拟化渲染、兼容 Expo (Snack)、深度自定义能力、使用 TypeScript 编写
二、基础用法
官方的 Expo 在线Demo案例:Quidone React Native Wheel Picker - Snack
安装
yarn add @quidone/react-native-wheel-picker
简单示例
示例效果图如上面的 Simple Picker 所示。
import React, {useState} from 'react';
import WheelPicker from '@quidone/react-native-wheel-picker';
const data = [...Array(100).keys()].map((index) => ({
value: index,
label: index.toString(),
}))
const App = () => {
const [value, setValue] = useState(0);
return (
<WheelPicker
data={data}
value={value}
onValueChanged={({item: {value}}) => setValue(value)}
enableScrollByTapOnItem={true}
/>
);
};
export default App;
WheelPicker 组件属性
| 属性名 | 描述 | 类型 | 默认值 |
|---|---|---|---|
data |
选择器的数据项数组 | Array<Item> |
必填 |
value |
当前选中的值 | any |
- |
itemHeight |
中间项的显示高度(单位:像素) | number |
40 |
visibleItemCount |
显示的项目数量(奇数:1, 3, 5...) | number |
5 |
width |
选择器宽度(数字或百分比字符串) | number | string |
'100%' |
readOnly |
是否只读模式(禁止交互) | boolean |
false |
enableScrollByTapOnItem |
是否允许点击项目触发滚动 | boolean |
false |
testID |
用于端到端测试的标识符 | string |
- |
onValueChanging |
值正在变化时触发的回调函数 | () => void |
- |
onValueChanged |
值改变后触发的回调(滚轮停止且无触摸时) | (event) => void |
- |
keyExtractor |
从数据项提取唯一key的函数 | (item: Item) => string |
使用value
|
renderItem |
自定义渲染项目内容的函数 | (props) => ReactNode |
显示label
|
renderItemContainer |
自定义渲染项目容器的函数(包含动画效果) | (props) => ReactNode |
默认容器 |
renderOverlay |
在选择器上方渲染覆盖层的函数 | () => ReactNode |
null |
renderList |
高级用法:自定义渲染整个列表(不建议使用) | (props) => ReactNode |
默认列表 |
style |
根容器的样式 | StyleProp<ViewStyle> |
- |
itemTextStyle |
项目文本的样式 | StyleProp<TextStyle> |
- |
overlayItemStyle |
中间覆盖元素(高亮区域)的样式 | StyleProp<ViewStyle> |
- |
contentContainerStyle |
包裹所有子视图的容器样式 | StyleProp<ViewStyle> |
- |
scrollEventThrottle |
滚动事件节流频率(单位:毫秒) | number |
16 |
其中,Item的类型如下:
type Item = {
value: any;
label: string;
// 可包含其他自定义字段
};
三、代码注释与实际效果展示(便于理解)
便于理解的代码(含注释)
import { Text, View } from 'tamagui'
import { SafeAreaView } from 'react-native-safe-area-context';
import { useState, memo, useMemo } from 'react';
import WheelPicker, {
usePickerItemHeight,
useScrollContentOffset,
} from '@quidone/react-native-wheel-picker';
import { Animated, StyleSheet } from 'react-native';
// data = [
// { value: 0, label: 'label0' },
// { value: 10, label: 'label1' },
// ...
// ]
const data = [...Array(100).keys()].map((index) => ({
value: index * 10, // 0, 10, 20, 30, ...
// 如果不指定renderItem属性,则默认渲染此label属性,label的值可以是jsx
label: 'label' + index, // 'label0', 'label1', 'label2', ...
}))
export default function APP() {
const [value, setValue] = useState(210); // 210: 指定首次渲染时Picker选中的item
return (
<SafeAreaView edges={['top']} style={{ backgroundColor: 'lightgray', flex: 1 }}>
<View borderWidth={1} borderColor='blue' bg='white' mx={20} items={'center'}>
<WheelPicker
width={300}
style={{
borderWidth: 1,
borderColor: 'red',
marginTop: 30,
overflow: 'hidden', // 必须设置overflow: 'hidden',否则实际区域下方仍然能触发点击效果
}}
data={data}
value={value}
visibleItemCount={5}
// itemHeight: “当前选中的区域的阴影”的高度 或者说 “实际每一项的高度”
// tip:选中区域的样式由renderOverlay属性决定(默认为阴影)
itemHeight={80}
onValueChanged={({ item, index }) => {
// item为data数组中的每一个对象
// index为data数组中的每一个对象的索引
setValue(item.value);
}}
// 渲染每一项,如果无renderItem,则默认渲染item的label属性(item.label)
renderItem={({ item, index, itemTextStyle }) => {
// item为data数组中的每一个对象
// index为data数组中的每一个对象的索引
// itemTextStyles为WheelPicker组件的itemTextStyle属性,感觉很鸡肋,可有可无
return (
// 最外层的height最好与WheelPicker组件的itemHeight属性值一致,这里故意不一致,看一下效果
<View borderWidth={index % 2 ? 1 : 0} borderColor='green' height={60}>
<Text>
{item.label}-{item.value}-{`index:${index}`}
</Text>
<Text style={itemTextStyle}>
{`${JSON.stringify(itemTextStyle)}`}
</Text>
</View>
)
}}
itemTextStyle={{ marginLeft: 20 }} // 一点用处没有,我没理解这个属性有什么实质性用处,可以直接忽略这个属性
// renderItemContainer的作用是:给item容器在滑动过程中设置动画,如果用他的默认动画,则不需要这个属性
// renderItemContainer={renderItemContainer}
// 渲染选中区域的样式(默认为阴影)
renderOverlay={({ itemHeight, overlayItemStyle }) => {
return (
<View pointerEvents={'none'} // pointerEvents={'none'} 必须有,否则会影响item的滑动
justify='center' style={StyleSheet.absoluteFillObject}
// bg={'#6982'}
>
<View height={itemHeight} style={overlayItemStyle} bg={'#0003'} />
</View>
);
}}
enableScrollByTapOnItem={true} //允许点击item后直接滚动至该item
/>
</View>
</SafeAreaView >
)
}
// renderItemContainer的作用是:给item容器在滑动过程中设置动画,如果用他的默认动画,则不需要这个属性
// 下面是官方的一个示例动画
const renderItemContainer = ({ renderItem, item, index, itemTextStyle, faces }) => {
const offset = useScrollContentOffset();
const height = usePickerItemHeight();
const inputRange = useMemo(
() => faces.map((f) => height * (index + f.index)),
[faces, height, index],
);
const { opacity, translateY, translateX } = useMemo(
() => ({
opacity: offset.interpolate({
inputRange: inputRange,
outputRange: faces.map((x) => x.opacity),
extrapolate: 'clamp',
}),
translateY: offset.interpolate({
inputRange: inputRange,
outputRange: faces.map((x) => x.offsetY),
extrapolate: 'extend',
}),
translateX: offset.interpolate({
inputRange: [
height * (index - 1),
height * index,
height * (index + 1),
],
outputRange: [-10, 0, -10],
extrapolate: 'extend',
}),
}),
[faces, height, index, inputRange, offset],
);
return (
<Animated.View
style={[{ height, opacity, transform: [{ translateY }, { translateX }] }]}
>
{renderItem({ item, index, itemTextStyle })}
</Animated.View>
);
}
效果展示
上述代码的实际效果如下图所示,所有的边框颜色都是为了便于理解。
* 四、官方给出的其他扩展性功能
其他扩展性功能,下面是官方提供的文档内容,没有实际需求的可以忽略。
触觉反馈功能
使用 @quidone/react-native-wheel-picker-feedback 配合 onValueChanging 事件来实现触觉反馈效果。
import WheelPickerFeedback from '@quidone/react-native-wheel-picker-feedback';
const App = () => {
return (
<WheelPicker
onValueChanging={() => {
WheelPickerFeedback.triggerSoundAndImpact();
}}
/>
);
};
扩展API
钩子函数
| API名称 | 描述 | 返回类型 |
|---|---|---|
usePickerItemHeight |
获取通过props传递的项目高度(响应式) | number |
useScrollContentOffset |
获取ScrollView的实时滚动偏移量(Animated.Value) | Animated.Value |
高阶组件
| API名称 | 描述 | 增强属性 |
|---|---|---|
withVirtualized |
为WheelPicker添加虚拟滚动能力 |
initialNumToRender等FlatList属性 |
import WheelPicker, {withVirtualized} from '@quidone/react-native-wheel-picker';
const VirtualizedWheelPicker = withVirtualized(WheelPicker);
额外属性
-
initialNumToRender?(默认 = Math.ceil(visibleItemCount / 2)) -
maxToRenderPerBatch?(默认 = Math.ceil(visibleItemCount / 2)) -
windowSize?- 原始属性 -
updateCellsBatchingPeriod?(默认 = 10) - 原始属性
五、原创项目效果展示
创作不易,如果有帮助到你,麻烦点个赞吧~~