import React, { FC, useRef } from 'react'; import { TouchableWithoutFeedback, Animated, Platform, StyleSheet } from 'react-native'; import { useControllableValue, useUpdateEffect } from '../hooks'; import { useThemeFactory } from '../Theme'; import Loading from '../Loading'; import createStyle from './style'; import type { SwitchProps } from './interface'; const Switch: FC = props => { const { loading, disabled, size, onPress, style, activeValue = true, inactiveValue = false, } = props; const [checked, setChecked] = useControllableValue(props, { valuePropName: 'checked', defaultValuePropName: 'defaultChecked', }); const { styles, theme } = useThemeFactory(createStyle, size); const isChecked = checked === activeValue; const translateXValueEnd = StyleSheet.flatten(styles.nodeRight).left as number; const translateXValueStart = StyleSheet.flatten(styles.nodeLeft).left as number; const duration = theme.switch_transition_duration; const translateX = useRef( new Animated.Value(isChecked ? translateXValueEnd : translateXValueStart) ).current; const onPressTouchable = () => { onPress?.(); if (!disabled && !loading) { const newValue = isChecked ? inactiveValue : activeValue; setChecked(newValue); } }; useUpdateEffect(() => { let actionAnimated: Animated.CompositeAnimation | null; actionAnimated = Animated.timing(translateX, { toValue: isChecked ? translateXValueEnd : translateXValueStart, duration, useNativeDriver: Platform.OS !== 'web', }); actionAnimated.start(() => { actionAnimated = null; }); return () => { // 停止动画 if (actionAnimated) { actionAnimated.stop(); actionAnimated = null; } }; }, [isChecked]); const activeColor = props.activeColor || theme.switch_on_background_color; const inactiveColor = props.inactiveColor || theme.switch_background_color; return ( {loading ? ( ) : null} ); }; export default Switch;