Skip to content

Instantly share code, notes, and snippets.

@cagils
Last active February 5, 2024 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cagils/3f00c1cff5ff429bdb4d1acee91bcc5e to your computer and use it in GitHub Desktop.
Save cagils/3f00c1cff5ff429bdb4d1acee91bcc5e to your computer and use it in GitHub Desktop.
React Native Breath In/Out Animation

This is a modified version of the Apple Watch like breathing animation from the video tutorial of Jimmy Cook. The animation goes full circle without going back and with easing in this one.

Demo Gif is after the gist code.

/ ====================================================================
// A MODIFIED VERSION OF THE APPLE WATCH LIKE BREATHING ANIMATION
// Cagil Seker [ÇAĞIL ŞEKER] (MadChuckle) - cagils@gmail.com
// ORIGINAL IDEA: Jimmy Cook (https://www.youtube.com/watch?v=dhF1kp0rGak)
// ====================================================================
import React, {useRef} from 'react';
import {Animated, Dimensions, Easing, StyleSheet, View} from 'react-native';
const {width, height} = Dimensions.get('window');
const circleSize = width / 2;
const App = () => {
const move = useRef(new Animated.Value(0)).current;
const breathIn = Easing.out(Easing.sin);
const breathOut = Easing.in(Easing.sin);
Animated.loop(
Animated.sequence([
Animated.timing(move, {
toValue: 1,
duration: 5000,
easing: breathIn,
useNativeDriver: true,
}),
Animated.timing(move, {
toValue: 2,
duration: 3000,
easing: breathOut,
useNativeDriver: true,
}),
Animated.timing(move, {
toValue: 0.0,
duration: 0,
useNativeDriver: true,
}),
]),
).start();
const translate = move.interpolate({
inputRange: [0, 1, 2],
outputRange: [0, circleSize / 6, 0],
});
return (
<View style={styles.container}>
<View
style={{
...StyleSheet.absoluteFill,
opacity: 0,
alignItems: 'center',
justifyContent: 'center',
}}>
<View
style={{
backgroundColor: 'blue',
width: circleSize,
height: circleSize,
borderRadius: circleSize / 2,
}}
/>
</View>
{[0, 1, 2, 3, 4, 5, 6, 7].map((item) => {
const rotation = move.interpolate({
inputRange: [0, 1, 2],
outputRange: [
`${item * 45}deg`, //
`${item * 45 + 180}deg`,
`${item * 45 + 360}deg`,
],
});
return (
<View
key={item}
style={{
...StyleSheet.absoluteFill,
alignItems: 'center',
justifyContent: 'center',
}}>
<Animated.View
style={{
opacity: 0.15,
backgroundColor: '#d600d3',
width: circleSize,
height: circleSize,
borderRadius: circleSize / 2,
transform: [
{
rotateZ: rotation,
},
{translateX: translate},
{translateY: translate},
],
}}
/>
</View>
);
})}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, //
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
@vinh8lequang
Copy link

This is great! Maybe if we add a breath-in/breath-out text in the middle or below to indicate the user how to breath would be a nice feature. Very neat!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment