@td-design/react-native-picker
Version:
基于 @td-design/react-native 的 picker 组件
128 lines (126 loc) • 4.28 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { Easing, Extrapolate, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated';
export default function WheelPicker(_ref) {
let {
itemHeight = 40,
data,
visibleRest = 5,
textStyle,
contentContainerStyle,
indicatorBgColor = 'rgba(0, 0, 0, 0.3)',
value,
onChange,
...props
} = _ref;
const initialIndex = value ? data.findIndex(item => item.value === value) : 0;
const translateY = useSharedValue(-itemHeight * initialIndex);
const snapPoints = new Array(data.length).fill(0).map((_, index) => -itemHeight * index);
const timingConfig = {
duration: 1000,
easing: Easing.bezier(0.35, 1, 0.35, 1)
};
const wrapper = index => {
onChange === null || onChange === void 0 ? void 0 : onChange(data[index], index);
};
const onGestureEvent = useAnimatedGestureHandler({
onStart(_, ctx) {
ctx.y = translateY.value;
},
onActive(event, ctx) {
translateY.value = ctx.y + event.translationY;
},
onEnd(event) {
const snapPointsY = snapPoint(translateY.value, event.velocityY, snapPoints);
const index = Math.abs(snapPointsY / itemHeight);
translateY.value = withTiming(snapPointsY, timingConfig);
runOnJS(wrapper)(index);
}
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [{
translateY: translateY.value
}]
}));
return /*#__PURE__*/React.createElement(View, _extends({}, props, {
style: styles.container
}), /*#__PURE__*/React.createElement(PanGestureHandler, {
onGestureEvent: onGestureEvent
}, /*#__PURE__*/React.createElement(Animated.View, {
style: [animatedStyle, contentContainerStyle, {
height: itemHeight * visibleRest,
paddingTop: (itemHeight * visibleRest - itemHeight) / 2
}]
}, data.map((data, index) => /*#__PURE__*/React.createElement(PickerItem, {
key: index,
translateY: translateY,
index: index,
itemHeight: itemHeight,
visibleRest: visibleRest,
data: data,
textStyle: textStyle
})))), /*#__PURE__*/React.createElement(View, {
style: {
width: '100%',
height: itemHeight,
backgroundColor: indicatorBgColor,
opacity: 0.2,
position: 'absolute'
},
pointerEvents: "none"
}));
}
function PickerItem(_ref2) {
let {
translateY,
index,
data,
itemHeight,
visibleRest,
textStyle
} = _ref2;
const y = useDerivedValue(() => interpolate(translateY.value / -itemHeight, [index - visibleRest / 2, index, index + visibleRest / 2], [-1, 0, 1], Extrapolate.CLAMP));
const textAnimation = useAnimatedStyle(() => ({
opacity: 1 / (1 + Math.abs(y.value)),
transform: [{
scale: 1 - Math.abs(y.value) * 0.35
}, {
perspective: 500
}, {
rotateX: `${y.value * 65}deg`
}]
}));
return /*#__PURE__*/React.createElement(Animated.View, {
style: [styles.item, {
height: itemHeight
}]
}, /*#__PURE__*/React.createElement(Animated.Text, {
style: [textAnimation, textStyle]
}, data.label));
}
const styles = StyleSheet.create({
container: {
flex: 1,
overflow: 'hidden',
justifyContent: 'center',
position: 'relative'
},
item: {
justifyContent: 'center',
alignItems: 'center'
}
});
/**
* @summary Select a point where the animation should snap to given the value of the gesture and it's velocity.
* @worklet
*/
const snapPoint = (value, velocity, points) => {
'worklet';
const point = value + 0.2 * velocity;
const deltas = points.map(p => Math.abs(point - p));
const minDelta = Math.min.apply(null, deltas);
return points.find(p => Math.abs(point - p) === minDelta) || points[0];
};
//# sourceMappingURL=index.js.map