Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
slug: flipCard | ||
title: Flip Card | ||
--- | ||
|
||
Flip card component is a component that allows you to display different content depending on whether the card is flipped or not. It can be especially useful when you do not want to display some data immediately after entering the screen (e.g. secure data) and only after fulfilling a certain condition or performing an action. | ||
|
||
import FlipCard from '@site/static/examples/FlipCard'; | ||
import FlipCardSrc from '!!raw-loader!@site/static/examples/FlipCard'; | ||
import ExampleVideo from '@site/src/components/ExampleVideo'; | ||
|
||
<InteractiveExample src={FlipCardSrc} component={<FlipCard />} /> | ||
|
||
For storing information about whether the card is flipped or not we use [shared value](/docs/fundamentals/glossary#shared-value) with the `useSharedValue` hook. Using shared values helps to prevent unnecessary re-renders. | ||
|
||
<CollapsibleCode src={FlipCardSrc} showLines={[111,111]} /> | ||
|
||
This allows us to [interpolate](/docs/utilities/interpolate) values between 0-180 and 180-360 degrees, depending on whether the card is flipped or not. In addition, we use [withTiming](/docs/animations/withTiming) util which makes our animation smooth. | ||
|
||
<CollapsibleCode src={FlipCardSrc} showLines={[56,58]} /> | ||
|
||
<ExampleVideo | ||
sources={{ | ||
android: "/react-native-reanimated/recordings/examples/flip_card_android.mov", | ||
ios: "/react-native-reanimated/recordings/examples/flip_card_ios.mov" | ||
}} | ||
/> | ||
|
||
The **FlipCard** component accepts several props: `duration` allows you to change the duration of the animation, setting `direction` to the value `x` allows you to change the direction of our animation, `RegularContent` and `FlippedContent` give ability to display different content for flipped and non flipped variants. | ||
|
||
<CollapsibleCode src={FlipCardSrc} showLines={[45,96]} /> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import React from 'react'; | ||
import { Pressable, SafeAreaView, View, StyleSheet, Text } from 'react-native'; | ||
import Animated, { | ||
interpolate, | ||
useAnimatedStyle, | ||
useSharedValue, | ||
withTiming, | ||
} from 'react-native-reanimated'; | ||
|
||
const RegularContent = () => { | ||
return ( | ||
<View style={regularContentStyles.card}> | ||
<Text>Regular content ✨</Text> | ||
</View> | ||
); | ||
}; | ||
|
||
const regularContentStyles = StyleSheet.create({ | ||
card: { | ||
flex: 1, | ||
backgroundColor: '#b6cff7', | ||
borderRadius: 16, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
}, | ||
}); | ||
|
||
const FlippedContent = () => { | ||
return ( | ||
<View style={flippedContentStyles.card}> | ||
<Text>Flipped content 🚀</Text> | ||
</View> | ||
); | ||
}; | ||
|
||
const flippedContentStyles = StyleSheet.create({ | ||
card: { | ||
flex: 1, | ||
backgroundColor: '#baeee5', | ||
borderRadius: 16, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
}, | ||
}); | ||
|
||
const FlipCard = ({ | ||
isFlipped, | ||
cardStyle, | ||
direction = 'y', | ||
duration = 500, | ||
RegularContent, | ||
FlippedContent, | ||
}) => { | ||
const isDirectionX = direction === 'x'; | ||
|
||
const regularCardAnimatedStyle = useAnimatedStyle(() => { | ||
const spinValue = interpolate(Number(isFlipped.value), [0, 1], [0, 180]); | ||
const rotateValue = withTiming(`${spinValue}deg`, { duration }); | ||
|
||
return { | ||
transform: [ | ||
isDirectionX ? { rotateX: rotateValue } : { rotateY: rotateValue }, | ||
], | ||
}; | ||
}); | ||
|
||
const flippedCardAnimatedStyle = useAnimatedStyle(() => { | ||
const spinValue = interpolate(Number(isFlipped.value), [0, 1], [180, 360]); | ||
const rotateValue = withTiming(`${spinValue}deg`, { duration }); | ||
|
||
return { | ||
transform: [ | ||
isDirectionX ? { rotateX: rotateValue } : { rotateY: rotateValue }, | ||
], | ||
}; | ||
}); | ||
|
||
return ( | ||
<View> | ||
<Animated.View | ||
style={[ | ||
flipCardStyles.regularCard, | ||
cardStyle, | ||
regularCardAnimatedStyle, | ||
]}> | ||
{RegularContent} | ||
</Animated.View> | ||
<Animated.View | ||
style={[ | ||
flipCardStyles.flippedCard, | ||
cardStyle, | ||
flippedCardAnimatedStyle, | ||
]}> | ||
{FlippedContent} | ||
</Animated.View> | ||
</View> | ||
); | ||
}; | ||
|
||
const flipCardStyles = StyleSheet.create({ | ||
regularCard: { | ||
position: 'absolute', | ||
zIndex: 1, | ||
}, | ||
flippedCard: { | ||
backfaceVisibility: 'hidden', | ||
zIndex: 2, | ||
}, | ||
}); | ||
|
||
export default function App() { | ||
const isFlipped = useSharedValue(false); | ||
|
||
const handlePress = () => { | ||
isFlipped.value = !isFlipped.value; | ||
}; | ||
|
||
return ( | ||
<SafeAreaView style={styles.container}> | ||
<FlipCard | ||
isFlipped={isFlipped} | ||
cardStyle={styles.flipCard} | ||
FlippedContent={<FlippedContent />} | ||
RegularContent={<RegularContent />} | ||
/> | ||
<View style={styles.buttonContainer}> | ||
<Pressable style={styles.toggleButton} onPress={handlePress}> | ||
<Text style={styles.toggleButtonText}>Toggle card</Text> | ||
</Pressable> | ||
</View> | ||
</SafeAreaView> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
height: 300, | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
}, | ||
buttonContainer: { | ||
marginTop: 16, | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
}, | ||
toggleButton: { | ||
backgroundColor: '#b58df1', | ||
padding: 12, | ||
borderRadius: 48, | ||
}, | ||
toggleButtonText: { | ||
color: '#fff', | ||
textAlign: 'center', | ||
}, | ||
flipCard: { | ||
width: 150, | ||
height: 200, | ||
}, | ||
}); |
Binary file not shown.
Binary file not shown.