Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/blog/switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
slug: switch
title: 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.

import Switch from '@site/static/examples/Switch';
import SwitchSrc from '!!raw-loader!@site/static/examples/Switch';
import ExampleVideo from '@site/src/components/ExampleVideo';
import CollapsibleCode from '@site/src/components/CollapsibleCode';

<InteractiveExample src={SwitchSrc} component={<Switch />} />

The following implementation of a switch relies on [animatable values](/docs/fundamentals/glossary#animatable-value). Leveraging animatable values of color and position enables smooth transition between the two states.

<samp id="Switch">Switch</samp>

<CollapsibleCode src={SwitchSrc} showLines={[26,52]}/>

<ExampleVideo
sources={{
android: "/react-native-reanimated/recordings/examples/switch_android.mp4",
ios: "/react-native-reanimated/recordings/examples/switch_ios.mov"
}}
/>

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.

<CollapsibleCode src={SwitchSrc} showLines={[23,25]}/>

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

<CollapsibleCode src={SwitchSrc} showLines={[56,61]}/>

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.

<samp id="Switch">Switch</samp>

<CollapsibleCode src={SwitchSrc} showLines={[16,67]}/>
120 changes: 120 additions & 0 deletions docs/static/examples/Switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React from 'react';
import {
Pressable,
SafeAreaView,
View,
StyleSheet,
Button,
} from 'react-native';
import Animated, {
interpolate,
interpolateColor,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated';

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>
);
};

const switchStyles = StyleSheet.create({
track: {
alignItems: 'flex-start',
width: 100,
height: 40,
padding: 5,
},
thumb: {
height: '100%',
aspectRatio: 1,
backgroundColor: 'white',
},
});

export default function App() {
const isOn = useSharedValue(false);

const handlePress = () => {
isOn.value = !isOn.value;
};

return (
<SafeAreaView style={styles.container}>
<Switch value={isOn} onPress={handlePress} style={styles.switch} />
<View style={styles.buttonContainer}>
<Button onPress={handlePress} title="Click me" />
</View>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
switch: {
width: 200,
height: 80,
padding: 10,
},
container: {
flex: 1,
height: 300,
alignItems: 'center',
justifyContent: 'center',
},
buttonContainer: {
paddingTop: '1rem',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
});
Binary file not shown.
Binary file added docs/static/recordings/examples/switch_ios.mov
Binary file not shown.