UNPKG

@fruits-chain/react-native-xiaoshu

Version:
130 lines (120 loc) 4.19 kB
import React, { useEffect, useState, useRef, memo } from 'react'; import { TouchableWithoutFeedback, Animated } from 'react-native'; import { useTheme, widthStyle } from '../theme'; import LoadingCircular from '../loading/circular'; import { useUpdateEffect } from '../hooks'; import { getDefaultValue, isPromise, isValue } from '../helpers'; import { createStyles } from './style'; /** * Switch 开关 * @description 用于在打开和关闭状态之间进行切换。 */ function Switch(_ref) { let { size, disabled = false, loading = false, value, defaultValue, activeValue = true, inactiveValue = false, inactiveColor, activeColor, onPress, onChange, beforeChange } = _ref; const translateX = useRef(new Animated.Value(0)); const [localValue, setLocalValue] = useState(isValue(value) ? value : isValue(defaultValue) ? defaultValue : inactiveValue); const THEME_VAR = useTheme(); const STYLES = widthStyle(THEME_VAR, createStyles); // 同步值 useUpdateEffect(() => { setLocalValue(value); }, [value]); const unitSize = getDefaultValue(size, THEME_VAR.switch_size); const switchWidth = unitSize * THEME_VAR.switch_width_ratio; const switchHeight = unitSize * THEME_VAR.switch_height_ratio; const nodeSize = unitSize * THEME_VAR.switch_node_size_ratio - THEME_VAR.switch_border_width * 2; const translateXValueEnd = switchWidth - nodeSize - THEME_VAR.switch_border_width * 2; const translateXValueStart = THEME_VAR.switch_border_width; const duration = THEME_VAR.switch_transition_duration; const active = localValue === activeValue; const onPressTouchable = () => { onPress === null || onPress === void 0 ? void 0 : onPress(); if (!disabled && !loading) { const newValue = active ? inactiveValue : activeValue; const doChange = () => { setLocalValue(newValue); onChange === null || onChange === void 0 ? void 0 : onChange(newValue); }; if (beforeChange) { const beforeChangeValue = beforeChange(newValue); if (isPromise(beforeChangeValue)) { beforeChangeValue.then(v => { if (v) { doChange(); } }); } else { if (beforeChangeValue) { doChange(); } } } else { doChange(); } } }; useEffect(() => { let actionValue; actionValue = Animated.timing(translateX.current, // 动画中的变量值 { toValue: active ? translateXValueEnd : translateXValueStart, duration: duration, useNativeDriver: false }); actionValue.start(_ref2 => { let { finished } = _ref2; if (finished) { actionValue = null; } }); return () => { // 停止动画 if (actionValue) { actionValue.stop(); actionValue = null; } }; }, [active, translateXValueStart, translateXValueEnd, duration]); const switchStyles = [STYLES.switch, { width: switchWidth, height: switchHeight, borderRadius: switchHeight / 2, // 当前过渡不支持 color/backgroundColor // 参考:https://stackoverflow.com/a/60586628 backgroundColor: active ? activeColor || THEME_VAR.switch_on_background_color : inactiveColor || THEME_VAR.switch_background_color }, disabled ? STYLES.disabled : null]; const nodeStyleSummary = [STYLES.node, { width: nodeSize, height: nodeSize, borderRadius: nodeSize / 2, transform: [{ translateX: translateX.current }] }]; return /*#__PURE__*/React.createElement(TouchableWithoutFeedback, { onPress: onPressTouchable }, /*#__PURE__*/React.createElement(Animated.View, { style: switchStyles }, /*#__PURE__*/React.createElement(Animated.View, { style: nodeStyleSummary }, loading ? /*#__PURE__*/React.createElement(LoadingCircular, { size: nodeSize / 4 * 3, color: active ? isValue(activeColor) ? activeColor : THEME_VAR.switch_on_background_color : isValue(inactiveColor) ? inactiveColor : THEME_VAR.loading_text_color }) : null))); } export default /*#__PURE__*/memo(Switch); //# sourceMappingURL=index.js.map