Skip to content

Commit

Permalink
added switch example (#5919)
Browse files Browse the repository at this point in the history
  • Loading branch information
alduzy authored Apr 22, 2024
1 parent 474f698 commit 849d490
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
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.

Check warning on line 15 in docs/blog/switch.md

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (animatable)

Check warning on line 15 in docs/blog/switch.md

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (animatable)

<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,

Check warning on line 3 in docs/static/examples/Switch.js

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (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}>

Check warning on line 56 in docs/static/examples/Switch.js

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (Pressable)
<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>

Check warning on line 66 in docs/static/examples/Switch.js

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (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.

0 comments on commit 849d490

Please sign in to comment.