再アニメーション化されたトグル機能を使用してカスタム スイッチ コンポーネントを作成しました。トグル機能は正常に動作し、onPress 関数をトグルして呼び出し、true または false を交互に返します。
initiStateが状態によって、または親からの新しい小道具によって変更されたときにトグル効果をアニメーション化したいと思います。助けてください、ありがとう。
Switch.tsx
import React, { useMemo } from 'react';
import { StyleSheet, Dimensions } from 'react-native';
import { timing, bInterpolate } from 'react-native-redash';
import { TapGestureHandler, State } from 'react-native-gesture-handler';
import Animated, { Easing } from 'react-native-reanimated';
interface SwitchProps {
onPress: (data: any) => void;
color: string;
background: string;
initState: boolean;
change: any;
}
const { height } = Dimensions.get('window');
const size = {
width: height >= 812 ? 60 : 50,
height: height >= 812 ? 35 : 30,
};
const {
Value,
useCode,
block,
cond,
eq,
set,
Clock,
clockRunning,
event,
sub,
stopClock,
onChange,
call,
and,
not,
} = Animated;
const Switch = ({
color,
onPress,
background: backgroundColor,
initState,
}: SwitchProps) => {
const { state, isOn, animate, shouldAnimate, width, clock } = useMemo(
() => ({
state: new Value(State.UNDETERMINED),
isOn: new Value(initState ? 1 : 0),
animate: new Value(initState ? 1 : 0),
clock: new Clock(),
shouldAnimate: new Value(0),
width: new Value(0),
}),
[]
);
useCode(() => {
return block([
cond(eq(state, State.END), set(shouldAnimate, 1)),
onChange(
state,
cond(
and(eq(state, State.END), not(clockRunning(clock))),
cond(
eq(isOn, 1),
call([], () => onPress(false)),
call([], () => onPress(true))
)
)
),
cond(and(eq(shouldAnimate, 1), eq(isOn, 0)), [
set(
animate,
timing({
from: animate,
to: 1,
duration: 100,
easing: Easing.linear,
clock,
})
),
cond(not(clockRunning(clock)), [set(shouldAnimate, 0), set(isOn, 1)]),
]),
cond(and(eq(shouldAnimate, 1), eq(isOn, 1)), [
set(
animate,
timing({
from: animate,
to: 0,
duration: 100,
easing: Easing.linear,
clock,
})
),
cond(not(clockRunning(clock)), [set(shouldAnimate, 0), set(isOn, 0)]),
]),
]);
}, [initState]);
const translateX = bInterpolate(animate, 0, sub(size.height - 10, width));
const backgroundWidth = bInterpolate(animate, 0, size.width);
return (
<TapGestureHandler
onHandlerStateChange={event([{ nativeEvent: { state } }])}>
<Animated.View
onLayout={event([
{
nativeEvent: { width },
},
])}
style={{
...size,
borderRadius: size.height / 2,
overflow: 'hidden',
backgroundColor: 'white',
}}>
<Animated.View
style={{
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
backgroundColor,
}}
/>
<Animated.View
style={{
flex: 1,
backgroundColor: color,
width: backgroundWidth,
}}
/>
<Animated.View
style={[styles.circle, { transform: [{ translateX }] }]}
/>
</Animated.View>
</TapGestureHandler>
);
};
const styles = StyleSheet.create({
circle: {
width: size.height - 2,
height: size.height - 2,
position: 'absolute',
left: 1,
top: 1,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.22,
shadowRadius: 2.22,
elevation: 3,
backgroundColor: 'white',
borderRadius: size.height - 2 / 2,
},
});
Switch.defaultProps = {
color: '#00000',
onPress: () => {},
initState: false,
background: '#8c8c8c',
change: [],
};
export default Switch;