Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added switch example #5919

Merged
merged 5 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
38 changes: 38 additions & 0 deletions docs/blog/switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
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.

<CollapsibleCode src={SwitchSrc} showLines={[26,52]}/>
patrycjakalinska marked this conversation as resolved.
Show resolved Hide resolved

<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.
patrycjakalinska marked this conversation as resolved.
Show resolved Hide resolved

<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 = 500,
patrycjakalinska marked this conversation as resolved.
Show resolved Hide resolved
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.