Skip to main content

Switch

A switch element is a user interface component that allows users to toggle between two or more states. It is commonly used to turn on/off a setting, enable/disable a feature, or select between options.

Loading...

The following implementation of a switch relies on animatable values. Leveraging animatable values of color and position enables smooth transition between the two states.

Switch
  const trackAnimatedStyle = useAnimatedStyle(() => {
const color = interpolateColor(
value.value,
[0, 1],
[trackColors.off, trackColors.on]
);
const colorValue = withTiming(color, { duration });

return {
backgroundColor: colorValue,
borderRadius: height.value / 2,
};
});

const thumbAnimatedStyle = useAnimatedStyle(() => {
const moveValue = interpolate(
Number(value.value),
[0, 1],
[0, width.value - height.value]
);
const translateValue = withTiming(moveValue, { duration });

return {
transform: [{ translateX: translateValue }],
borderRadius: height.value / 2,
};
});

We use the useSharedValue hook to store the dimensions of the element, which allows for precise calculation of position changes during the animation. The hook is there to prevent unnecessary re-renders.

  const height = useSharedValue(0);
const width = useSharedValue(0);

The values are updated during the onLayout event of the element.

      <Animated.View
onLayout={(e) => {
height.value = e.nativeEvent.layout.height;
width.value = e.nativeEvent.layout.width;
}}
style={[switchStyles.track, style, trackAnimatedStyle]}>

The Switch component can represent any boolean value passed as a prop. The state dynamically adjusts based on the value prop resulting in smooth transition animations. It enables passing any function using the onPress prop. The duration prop controls the duration of the animation. The style and trackColors props enable personalization.

Switch
const Switch = ({
value,
onPress,
style,
duration = 400,
trackColors = { on: '#82cab2', off: '#fa7f7c' },
}) => {
const height = useSharedValue(0);
const width = useSharedValue(0);

const trackAnimatedStyle = useAnimatedStyle(() => {
const color = interpolateColor(
value.value,
[0, 1],
[trackColors.off, trackColors.on]
);
const colorValue = withTiming(color, { duration });

return {
backgroundColor: colorValue,
borderRadius: height.value / 2,
};
});

const thumbAnimatedStyle = useAnimatedStyle(() => {
const moveValue = interpolate(
Number(value.value),
[0, 1],
[0, width.value - height.value]
);
const translateValue = withTiming(moveValue, { duration });

return {
transform: [{ translateX: translateValue }],
borderRadius: height.value / 2,
};
});

return (
<Pressable onPress={onPress}>
<Animated.View
onLayout={(e) => {
height.value = e.nativeEvent.layout.height;
width.value = e.nativeEvent.layout.width;
}}
style={[switchStyles.track, style, trackAnimatedStyle]}>
<Animated.View
style={[switchStyles.thumb, thumbAnimatedStyle]}></Animated.View>
</Animated.View>
</Pressable>
);
};