Skip to content

Instantly share code, notes, and snippets.

@mattThousand
Last active January 17, 2021 01:01
Show Gist options
  • Save mattThousand/1e1b8847d60914bb5638ad0526c3356b to your computer and use it in GitHub Desktop.
Save mattThousand/1e1b8847d60914bb5638ad0526c3356b to your computer and use it in GitHub Desktop.
import { BlurView } from 'expo-blur';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { View, StyleSheet, Dimensions, Animated, Pressable, Text, Easing } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
const { width, height } = Dimensions.get('screen');
const BreathAnimation: FunctionComponent = () => {
const animatedScale = React.useRef(new Animated.Value(1)).current;
const animatedLeftText = React.useRef(new Animated.Value(10)).current;
const [leftText, setLeftText] = useState('');
const [rightText, setRightText] = useState('');
const [animationState, setAnimationState] = useState<AnimationState>('initial');
type AnimationState = 'initial' | 'breathIn' | 'breathOut' | 'pause';
const animate = () => {
Animated.parallel([animateLeftText(), animateScale()]).start(() => animatedLeftText.setValue(10));
};
const animateLeftText = () => {
return Animated.sequence([
Animated.timing(animatedLeftText, {
toValue: 5,
duration: 4000,
easing: Easing.linear,
useNativeDriver: true,
}),
Animated.delay(2000),
Animated.timing(animatedLeftText, {
toValue: 0,
duration: 4000,
easing: Easing.linear,
useNativeDriver: true,
}),
]);
};
const animateScale = () => {
return Animated.sequence([
Animated.timing(animatedScale, {
toValue: 1.4,
duration: 4000,
useNativeDriver: true,
}),
Animated.delay(2000),
Animated.timing(animatedScale, {
toValue: 1,
duration: 4000,
useNativeDriver: true,
}),
]);
};
const handlePress = () => animate();
useEffect(() => {
if (animationState === 'initial') {
setRightText('');
} else if (animationState === 'breathIn') {
setRightText('Breath in');
} else if (animationState === 'breathOut') {
setRightText('Breath out');
} else if (animationState === 'pause') {
setRightText('Pause');
}
}, [animationState]);
useEffect(() => {
animatedLeftText.addListener((value) => {
if (value.value > 0) {
setLeftText(Math.ceil(value.value).toString());
}
if (value.value === 10) {
setAnimationState('initial');
} else if (value.value > 5) {
setAnimationState('breathIn');
} else if (value.value < 5) {
setAnimationState('breathOut');
} else {
setAnimationState('pause');
}
});
return () => {
animatedLeftText.removeAllListeners();
};
}, []);
return (
<View style={style.container}>
<Animated.View style={[style.circle, { transform: [{ scale: animatedScale }] }]}>
<LinearGradient colors={['yellow', 'red', 'purple']} style={style.gradient} />
</Animated.View>
<BlurView tint={'dark'} intensity={80} style={style.blurview} />
<Text style={style.leftText}>{leftText}</Text>
<Text style={style.rightText}>{rightText}</Text>
<Pressable onPress={handlePress} style={[style.circle, style.pressable]} />
</View>
);
};
const style = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
blurview: {
width,
height: height / 2,
position: 'absolute',
bottom: 0,
},
circle: {
width: 250,
height: 250,
borderRadius: 150,
overflow: 'hidden',
},
gradient: {
width: 250,
height: 250,
},
pressable: {
position: 'absolute',
},
leftText: {
position: 'absolute',
color: '#fff',
fontSize: 70,
bottom: 50,
left: 50,
},
rightText: {
position: 'absolute',
color: '#fff',
fontSize: 40,
bottom: 70,
right: 20,
},
});
export default BreathAnimation;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment