|
import React, { useState } from 'react'; |
|
import { Pressable, Text } from 'react-native'; |
|
import Animated, { css } from 'react-native-reanimated'; |
|
|
|
export default function ParticleButton() { |
|
const [pressed, setPressed] = useState(false); |
|
const [showParticles, setShowParticles] = useState(false); |
|
|
|
return ( |
|
<Pressable |
|
onPressIn={() => setPressed(true)} |
|
onPressOut={() => setPressed(false)} |
|
onPress={() => setShowParticles(!showParticles)} |
|
style={{ marginTop: 30 }} |
|
> |
|
<Animated.View |
|
style={[ |
|
styles.button, |
|
pressed ? styles.animationDown : styles.animationUp, |
|
showParticles ? { backgroundColor: 'rgb(43, 192, 92)' } : { backgroundColor: 'rgb(227, 57, 57)' }, |
|
]} |
|
> |
|
<Text style={styles.text}> |
|
{showParticles ? '🎉' : '+'} |
|
</Text> |
|
</Animated.View> |
|
<Animated.View style={[ |
|
styles.buttonBackground, |
|
showParticles ? { backgroundColor: 'rgb(22, 137, 41)' } : { backgroundColor: 'rgb(172, 41, 41)' }, |
|
]} /> |
|
{[ |
|
{ x: -40, y: -40 }, |
|
{ x: 40, y: -70 }, |
|
{ x: 120, y: -40 }, |
|
{ x: 160, y: 40 }, |
|
{ x: 120, y: 120 }, |
|
{ x: 40, y: 160 }, |
|
{ x: -40, y: 120 }, |
|
{ x: -80, y: 40 }, |
|
].map((position, index) => { |
|
return <Particle key={index} x={position.x} y={position.y} state={showParticles} />; |
|
})} |
|
</Pressable> |
|
); |
|
} |
|
|
|
function Particle({ x, y, state }: { x: number, y: number, state: boolean }) { |
|
return ( |
|
<Animated.View |
|
style={[ |
|
styles.particle, |
|
{ transform: [{ translateX: x }, { translateY: y }]}, |
|
state ? styles.particleDown : styles.particleUp, |
|
]} |
|
/> |
|
); |
|
} |
|
|
|
const styles = css.create({ |
|
button: { |
|
transitionProperty: 'all', |
|
transitionDuration: 200, |
|
borderRadius: '100%', |
|
width: 100, |
|
height: 100, |
|
justifyContent: 'center', |
|
alignItems: 'center', |
|
}, |
|
buttonBackground: { |
|
transitionProperty: 'all', |
|
transitionDuration: 200, |
|
borderRadius: '100%', |
|
width: 100, |
|
height: 100, |
|
transform: [{ translateY: -90 }], |
|
zIndex: -1, |
|
}, |
|
text: { |
|
color: 'white', |
|
fontSize: 50, |
|
textAlign: 'center', |
|
fontWeight: 'bold', |
|
}, |
|
particle: { |
|
backgroundColor: 'rgb(7, 205, 69)', |
|
borderRadius: '100%', |
|
width: 20, |
|
height: 20, |
|
zIndex: -2, |
|
position: 'absolute', |
|
}, |
|
|
|
animationDown: { |
|
animationDuration: 150, |
|
animationTimingFunction: 'easeIn', |
|
animationFillMode: 'forwards', |
|
animationName: { |
|
'0%': { transform: [{ translateY: 0 }] }, |
|
'100%': { transform: [{ translateY: 7 }] }, |
|
}, |
|
}, |
|
animationUp: { |
|
animationDuration: 150, |
|
animationTimingFunction: 'easeOut', |
|
animationFillMode: 'forwards', |
|
animationName: { |
|
'0%': { transform: [{ translateY: 7 }] }, |
|
'100%': { transform: [{ translateY: 0 }] }, |
|
}, |
|
}, |
|
|
|
particleDown: { |
|
animationDuration: 600, |
|
animationTimingFunction: 'easeOut', |
|
animationFillMode: 'both', |
|
animationName: { |
|
'0%': { transform: [{ translateY: 50 }, { translateX: 40 }], opacity: 1 }, |
|
'30%': { opacity: 1 }, |
|
'100%': { opacity: 0 }, |
|
}, |
|
}, |
|
particleUp: { |
|
opacity: 0, |
|
}, |
|
}); |