├── .babelrc ├── .eslintrc ├── .gitignore ├── .watchmanconfig ├── assets ├── icons │ ├── app.png │ └── loading.png └── screenshots │ └── demo.png ├── exp.json ├── jsconfig.json ├── main.js ├── package.json ├── readme.md ├── src ├── App.js ├── Navigator.js ├── animations │ ├── AnimatedBasic.js │ ├── BouncingHeart.js │ ├── CollapseHeader.js │ ├── ColorBox.js │ ├── CommentModal.js │ ├── EventCard.js │ ├── FloatingHeart.js │ ├── MagicButton.js │ ├── MagicCard.js │ ├── MagicInput.js │ ├── ParallaxScrollview.js │ ├── SpringyMenu.js │ ├── assets │ │ └── images │ │ │ ├── 1.jpeg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpeg │ │ │ ├── 4.jpeg │ │ │ └── beansable.png │ └── components │ │ ├── heart.js │ │ └── moment.js ├── components │ ├── Info.js │ ├── List.js │ └── StatusBar.js └── icons │ ├── BackIcon.js │ ├── HelpIcon.js │ ├── MenuIcon.js │ ├── OpenIcon.js │ └── ShareIcon.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["babel-preset-expo"], 3 | "env": { 4 | "development": { 5 | "plugins": ["transform-react-jsx-source"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "equimper" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | .vscode/ 5 | .DS_Store -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /assets/icons/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/assets/icons/app.png -------------------------------------------------------------------------------- /assets/icons/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/assets/icons/loading.png -------------------------------------------------------------------------------- /assets/screenshots/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/assets/screenshots/demo.png -------------------------------------------------------------------------------- /exp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animations", 3 | "description": "An empty new project", 4 | "slug": "react-native-animations", 5 | "privacy": "public", 6 | "sdkVersion": "16.0.0", 7 | "version": "1.0.0", 8 | "orientation": "portrait", 9 | "primaryColor": "#cccccc", 10 | "icon": "./assets/icons/app.png", 11 | "loading": { 12 | "icon": "./assets/icons/loading.png", 13 | "hideExponentText": false 14 | }, 15 | "packagerOpts": { 16 | "assetExts": ["ttf", "mp4"] 17 | }, 18 | "ios": { 19 | "supportsTablet": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true 5 | }, 6 | "exclude": [ 7 | "node_modules" 8 | ] 9 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import Expo from 'expo'; 2 | 3 | import App from './src/App'; 4 | 5 | Expo.registerRootComponent(App); 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animations", 3 | "version": "0.0.0", 4 | "description": "Hello Expo!", 5 | "author": null, 6 | "private": true, 7 | "main": "main.js", 8 | "dependencies": { 9 | "expo": "16.0.0", 10 | "react": "16.0.0-alpha.6", 11 | "react-native": "https://github.com/expo/react-native/archive/sdk-16.0.0.tar.gz", 12 | "react-navigation": "^1.0.0-beta.11" 13 | }, 14 | "devDependencies": { 15 | "eslint": "^4.0.0", 16 | "eslint-config-equimper": "^2.1.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # React Native Animations Collection 2 | > A beautiful collection of React Native animations linked with Github 🐬. 3 | React Native Animations 4 | 5 | ## Demo 6 | - Published App using Expo: [https://exp.host/@bkdev/react-native-animations](https://exp.host/@bkdev/react-native-animations) 7 | - Standalone App: `Comming Soon!` 8 | 9 | ## Development 10 | This app was wrapped using [Expo](https://expo.io). 11 | Clone the repo, `yarn`, `exp start`, `exp ios` then open folder with any [code](http://blog.bkdev.me/2017/04/11/vscode.html) editors and you are ready to have fun 🍻. 12 | 13 | I just made the whole stuffs in one day so feel free making issues and pull requests, you are so welcome! 🙌🏻 14 | 15 | ## Tutorials 16 | Comming soon on [Beansable Team](https://beansable.com). -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View } from 'react-native'; 3 | 4 | import Navigator from './Navigator'; 5 | import StatusBar from './components/StatusBar'; 6 | 7 | const App = () => ( 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /src/Navigator.js: -------------------------------------------------------------------------------- 1 | import { 2 | StackNavigator, 3 | } from 'react-navigation'; 4 | 5 | import List from './components/List'; 6 | import AnimatedBasic from './animations/AnimatedBasic'; 7 | import MagicButton from './animations/MagicButton'; 8 | import MagicCard from './animations/MagicCard'; 9 | import ColorBox from './animations/ColorBox'; 10 | import ParallaxScrollview from './animations/ParallaxScrollview'; 11 | import BouncingHeart from './animations/BouncingHeart'; 12 | import SpringyMenu from './animations/SpringyMenu'; 13 | import CommentModal from './animations/CommentModal'; 14 | import FloatingHeart from './animations/FloatingHeart'; 15 | import EventCard from './animations/EventCard'; 16 | import CollapseHeader from './animations/CollapseHeader'; 17 | import MagicInput from './animations/MagicInput'; 18 | 19 | const Navigator = StackNavigator({ 20 | List: { screen: List }, 21 | AnimatedBasic: { screen: AnimatedBasic }, 22 | MagicButton: { screen: MagicButton }, 23 | MagicCard: { screen: MagicCard }, 24 | ColorBox: { screen: ColorBox }, 25 | ParallaxScrollview: { screen: ParallaxScrollview }, 26 | BouncingHeart: { screen: BouncingHeart }, 27 | SpringyMenu: { screen: SpringyMenu }, 28 | CommentModal: { screen: CommentModal }, 29 | FloatingHeart: { screen: FloatingHeart }, 30 | EventCard: { screen: EventCard }, 31 | CollapseHeader: { screen: CollapseHeader }, 32 | MagicInput: { screen: MagicInput }, 33 | }); 34 | 35 | export default Navigator; 36 | -------------------------------------------------------------------------------- /src/animations/AnimatedBasic.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | Animated, 6 | Easing, 7 | Linking, 8 | } from 'react-native'; 9 | 10 | import BackIcon from '../icons/BackIcon'; 11 | import OpenIcon from '../icons/OpenIcon'; 12 | 13 | class AnimatedBasic extends Component { 14 | static navigationOptions = ({ navigation }) => ({ 15 | headerTitle: 'Animated Basic', 16 | headerStyle: { 17 | height: 80, 18 | backgroundColor: '#EC407A', 19 | justifyContent: 'center', 20 | }, 21 | headerTitleStyle: { 22 | color: 'white', 23 | fontSize: 20, 24 | fontWeight: '400', 25 | }, 26 | headerLeft: navigation.goBack()} />, 27 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/AnimatedBasic.js')} />, 28 | }) 29 | 30 | componentWillMount() { 31 | this.animatedValue = new Animated.Value(100); 32 | } 33 | 34 | componentDidMount() { 35 | Animated.timing(this.animatedValue, { 36 | toValue: 150, 37 | duration: 3000, 38 | easing: Easing.bounce, 39 | }).start(); 40 | } 41 | 42 | render() { 43 | const animatedStyle = { height: this.animatedValue }; 44 | return ( 45 | 46 | 47 | 48 | ); 49 | } 50 | } 51 | 52 | const styles = StyleSheet.create({ 53 | container: { 54 | flex: 1, 55 | justifyContent: 'center', 56 | alignItems: 'center', 57 | }, 58 | root: { 59 | width: 100, 60 | height: 100, 61 | backgroundColor: '#b1bb', 62 | }, 63 | }); 64 | 65 | export default AnimatedBasic; 66 | -------------------------------------------------------------------------------- /src/animations/BouncingHeart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | Animated, 6 | TouchableWithoutFeedback, 7 | Linking, 8 | } from 'react-native'; 9 | 10 | import BackIcon from '../icons/BackIcon'; 11 | import OpenIcon from '../icons/OpenIcon'; 12 | import Heart from './components/heart'; 13 | 14 | const getTransformationAnimation = (animation, scale, y, x, rotate, opacity) => { 15 | const scaleAnimation = animation.interpolate({ 16 | inputRange: [0, 1], 17 | outputRange: [0, scale], 18 | }); 19 | 20 | const xAnimation = animation.interpolate({ 21 | inputRange: [0, 1], 22 | outputRange: [0, x], 23 | }); 24 | 25 | const yAnimation = animation.interpolate({ 26 | inputRange: [0, 1], 27 | outputRange: [0, y], 28 | }); 29 | 30 | const rotateAnimation = animation.interpolate({ 31 | inputRange: [0, 1], 32 | outputRange: ['0deg', rotate], 33 | }); 34 | 35 | const opacityAnimation = animation.interpolate({ 36 | inputRange: [0, 1], 37 | outputRange: [0, opacity], 38 | }); 39 | 40 | return { 41 | opacity: opacityAnimation, 42 | transform: [ 43 | { scale: scaleAnimation }, 44 | { translateX: xAnimation }, 45 | { translateY: yAnimation }, 46 | { rotate: rotateAnimation }, 47 | ], 48 | }; 49 | }; 50 | 51 | class BouncingHeart extends Component { 52 | static navigationOptions = ({ navigation }) => ({ 53 | headerTitle: 'Bouncing Heart', 54 | headerStyle: { 55 | height: 80, 56 | backgroundColor: '#EC407A', 57 | justifyContent: 'center', 58 | }, 59 | headerTitleStyle: { 60 | color: 'white', 61 | fontSize: 20, 62 | fontWeight: '400', 63 | }, 64 | headerLeft: navigation.goBack()} />, 65 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/BouncingHeart.js')} />, 66 | }) 67 | 68 | constructor(props) { 69 | super(props); 70 | this.state = { 71 | liked: false, 72 | scale: new Animated.Value(0), 73 | animations: [ 74 | new Animated.Value(0), 75 | new Animated.Value(0), 76 | new Animated.Value(0), 77 | new Animated.Value(0), 78 | new Animated.Value(0), 79 | new Animated.Value(0), 80 | ], 81 | }; 82 | } 83 | 84 | triggerLike = () => { 85 | this.setState({ 86 | liked: !this.state.liked, 87 | }); 88 | 89 | const showAnimations = this.state.animations.map((animation) => Animated.spring(animation, { 90 | toValue: 1, 91 | friction: 4, 92 | })); 93 | 94 | const hideAnimations = this.state.animations.map((animation) => Animated.timing(animation, { 95 | toValue: 0, 96 | duration: 50, 97 | })).reverse(); 98 | 99 | Animated.parallel([ 100 | Animated.spring(this.state.scale, { 101 | toValue: 2, 102 | friction: 3, 103 | }), 104 | Animated.sequence([ 105 | Animated.stagger(50, showAnimations), 106 | Animated.delay(100), 107 | Animated.stagger(50, hideAnimations), 108 | ]), 109 | ]).start(() => { 110 | this.state.scale.setValue(0); 111 | }); 112 | } 113 | 114 | render() { 115 | const bouncyHeart = this.state.scale.interpolate({ 116 | inputRange: [0, 1, 2], 117 | outputRange: [1, 0.8, 1], 118 | }); 119 | 120 | const heartButtonStyle = { 121 | transform: [ 122 | { scale: bouncyHeart }, 123 | ], 124 | }; 125 | 126 | return ( 127 | 128 | 129 | 133 | 137 | 141 | 145 | 149 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | ); 161 | } 162 | } 163 | 164 | const styles = StyleSheet.create({ 165 | container: { 166 | flex: 1, 167 | justifyContent: 'center', 168 | alignItems: 'center', 169 | }, 170 | heart: { 171 | position: 'absolute', 172 | top: 0, 173 | left: 0, 174 | }, 175 | }); 176 | 177 | export default BouncingHeart; 178 | -------------------------------------------------------------------------------- /src/animations/CollapseHeader.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Animated, 5 | StyleSheet, 6 | Linking, 7 | Text, 8 | ScrollView, 9 | } from 'react-native'; 10 | 11 | import Beansable from './assets/images/beansable.png'; 12 | import BackIcon from '../icons/BackIcon'; 13 | import OpenIcon from '../icons/OpenIcon'; 14 | 15 | class CollapseHeader extends Component { 16 | static navigationOptions = ({ navigation }) => ({ 17 | headerTitle: 'Collapse Header', 18 | headerStyle: { 19 | height: 80, 20 | backgroundColor: '#EC407A', 21 | justifyContent: 'center', 22 | }, 23 | headerTitleStyle: { 24 | color: 'white', 25 | fontSize: 20, 26 | fontWeight: '400', 27 | }, 28 | headerLeft: navigation.goBack()} />, 29 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/CollapseHeader.js')} />, 30 | }) 31 | 32 | componentWillMount() { 33 | this.animated = new Animated.Value(0); 34 | } 35 | 36 | render() { 37 | const hideImageInterpolate = this.animated.interpolate({ 38 | inputRange: [0, 150], 39 | outputRange: [50, 0], 40 | extrapolate: 'clamp', 41 | }); 42 | 43 | const fontInterpolate = this.animated.interpolate({ 44 | inputRange: [0, 150], 45 | outputRange: [15, 20], 46 | }); 47 | 48 | const opacityInterpolate = this.animated.interpolate({ 49 | inputRange: [0, 150], 50 | outputRange: [1, 0], 51 | extrapolate: 'clamp', 52 | }); 53 | 54 | const collapseInterpolate = this.animated.interpolate({ 55 | inputRange: [0, 150], 56 | outputRange: [30, 0], 57 | extrapolate: 'clamp', 58 | }); 59 | 60 | const imageStyle = { 61 | width: hideImageInterpolate, 62 | height: hideImageInterpolate, 63 | }; 64 | 65 | const titleStyle = { 66 | fontSize: fontInterpolate, 67 | }; 68 | 69 | const fadeButtonStyle = { 70 | opacity: opacityInterpolate, 71 | height: collapseInterpolate, 72 | }; 73 | 74 | return ( 75 | 76 | 77 | 78 | Beansable 79 | 80 | 81 | Articles 82 | 83 | 84 | Contact 85 | 86 | 87 | 88 | 89 | 95 | 96 | top 97 | 98 | 99 | 100 | 101 | ); 102 | } 103 | } 104 | 105 | const styles = StyleSheet.create({ 106 | container: { 107 | flex: 1, 108 | }, 109 | header: { 110 | backgroundColor: '#F06292', 111 | alignItems: 'center', 112 | padding: 10, 113 | }, 114 | logoImage: { 115 | width: 50, 116 | height: 50, 117 | }, 118 | title: { 119 | color: 'rgba(255,255,255,.8)', 120 | fontSize: 15, 121 | }, 122 | buttons: { 123 | flexDirection: 'row', 124 | }, 125 | button: { 126 | flex: 5, 127 | justifyContent: 'center', 128 | alignItems: 'center', 129 | }, 130 | buttonText: { 131 | color: 'rgba(255,255,255,.5)', 132 | fontSize: 15, 133 | }, 134 | scrollView: { 135 | }, 136 | fakeContent: { 137 | padding: 20, 138 | height: 800, 139 | alignItems: 'center', 140 | }, 141 | fakeText: { 142 | fontSize: 25, 143 | color: '#F8BBD0', 144 | }, 145 | }); 146 | 147 | export default CollapseHeader; 148 | -------------------------------------------------------------------------------- /src/animations/ColorBox.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Animated, 5 | StyleSheet, 6 | Linking, 7 | } from 'react-native'; 8 | 9 | import BackIcon from '../icons/BackIcon'; 10 | import OpenIcon from '../icons/OpenIcon'; 11 | 12 | class ColorBox extends Component { 13 | static navigationOptions = ({ navigation }) => ({ 14 | headerTitle: 'Color Box', 15 | headerStyle: { 16 | height: 80, 17 | backgroundColor: '#EC407A', 18 | justifyContent: 'center', 19 | }, 20 | headerTitleStyle: { 21 | color: 'white', 22 | fontSize: 20, 23 | fontWeight: '400', 24 | }, 25 | headerLeft: navigation.goBack()} />, 26 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/ColorBox.js')} />, 27 | }) 28 | 29 | componentWillMount() { 30 | this.animatedValue = new Animated.Value(0); 31 | } 32 | 33 | componentDidMount() { 34 | Animated.timing(this.animatedValue, { 35 | toValue: 150, 36 | duration: 1500, 37 | }).start(); 38 | } 39 | 40 | render() { 41 | const interpolateColor = this.animatedValue.interpolate({ 42 | inputRange: [0, 150], 43 | outputRange: ['#FCE4EC', '#E91E63'], 44 | }); 45 | 46 | const animatedStyle = { 47 | backgroundColor: interpolateColor, 48 | transform: [ 49 | { translateY: this.animatedValue }, 50 | ], 51 | }; 52 | 53 | return ( 54 | 55 | 56 | 57 | ); 58 | } 59 | } 60 | 61 | const styles = StyleSheet.create({ 62 | container: { 63 | flex: 1, 64 | justifyContent: 'center', 65 | alignItems: 'center', 66 | }, 67 | box: { 68 | width: 100, 69 | height: 100, 70 | }, 71 | }); 72 | 73 | export default ColorBox; 74 | -------------------------------------------------------------------------------- /src/animations/CommentModal.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Animated, 5 | StyleSheet, 6 | Linking, 7 | ScrollView, 8 | Text, 9 | TextInput, 10 | PanResponder, 11 | } from 'react-native'; 12 | 13 | import BackIcon from '../icons/BackIcon'; 14 | import OpenIcon from '../icons/OpenIcon'; 15 | 16 | class CommentModal extends Component { 17 | static navigationOptions = ({ navigation }) => ({ 18 | headerTitle: 'Comment Modal', 19 | headerStyle: { 20 | height: 80, 21 | backgroundColor: '#EC407A', 22 | justifyContent: 'center', 23 | }, 24 | headerTitleStyle: { 25 | color: 'white', 26 | fontSize: 20, 27 | fontWeight: '400', 28 | }, 29 | headerLeft: navigation.goBack()} />, 30 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/CommentModal.js')} />, 31 | }) 32 | 33 | componentWillMount() { 34 | this.animated = new Animated.Value(0); 35 | this.animatedMargin = new Animated.Value(0); 36 | this.scrollOffset = 0; 37 | this.contentHeight = 0; 38 | this.scrollViewHeight = 0; 39 | 40 | this.panResponder = PanResponder.create({ 41 | onMoveShouldSetPanResponder: (evt, gestureState) => { 42 | const { dy } = gestureState; 43 | const totalScrollHeight = this.scrollOffset + this.scrollViewHeight; 44 | 45 | if ( 46 | (this.scrollOffset <= 0 && dy > 0) || 47 | ((totalScrollHeight >= this.contentHeight) && dy < 0) 48 | ) return true; 49 | }, 50 | onPanResponderMove: (e, gestureState) => { 51 | const { dy } = gestureState; 52 | if (dy < 0) { 53 | this.animated.setValue(dy); 54 | } else if (dy > 0) { 55 | this.animatedMargin.setValue(dy); 56 | } 57 | }, 58 | onPanResponderRelease: (e, gestureState) => { 59 | const { dy } = gestureState; 60 | 61 | if (dy < -150) { 62 | Animated.parallel([ 63 | Animated.timing(this.animated, { 64 | toValue: -550, 65 | duration: 150, 66 | }), 67 | Animated.timing(this.animatedMargin, { 68 | toValue: 0, 69 | duration: 150, 70 | }), 71 | ]).start(); 72 | } else if (dy > -150 && dy < 150) { 73 | Animated.parallel([ 74 | Animated.timing(this.animated, { 75 | toValue: 0, 76 | duration: 150, 77 | }), 78 | Animated.timing(this.animatedMargin, { 79 | toValue: 0, 80 | duration: 150, 81 | }), 82 | ]).start(); 83 | } else if (dy > 150) { 84 | Animated.timing(this.animated, { 85 | toValue: 550, 86 | duration: 300, 87 | }).start(); 88 | } 89 | }, 90 | }); 91 | } 92 | 93 | render() { 94 | const spacerStyle = { 95 | marginTop: this.animatedMargin, 96 | }; 97 | 98 | const opacityInterpolate = this.animated.interpolate({ 99 | inputRange: [-500, 0, 500], 100 | outputRange: [0, 1, 0], 101 | }); 102 | 103 | const modalStyle = { 104 | transform: [ 105 | { translateY: this.animated }, 106 | ], 107 | opacity: opacityInterpolate, 108 | }; 109 | 110 | return ( 111 | 112 | 113 | 117 | 118 | { 121 | this.scrollOffset = event.nativeEvent.contentOffset.y; 122 | this.scrollViewHeight = event.nativeEvent.layoutMeasurement.height; 123 | }} 124 | onContentSizeChange={(contentWidth, contentHeight) => { 125 | this.contentHeight = contentHeight; 126 | }} 127 | > 128 | Top 129 | 130 | Bottom 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | ); 139 | } 140 | } 141 | 142 | const styles = StyleSheet.create({ 143 | container: { 144 | flex: 1, 145 | justifyContent: 'center', 146 | alignItems: 'center', 147 | }, 148 | modal: { 149 | width: 350, 150 | height: 500, 151 | borderColor: '#F8BBD0', 152 | borderWidth: 2, 153 | }, 154 | comments: { 155 | flex: 9.5, 156 | }, 157 | fakeComments: { 158 | height: 500, 159 | }, 160 | fakeText: { 161 | textAlign: 'center', 162 | color: '#F06292', 163 | fontSize: 20, 164 | paddingVertical: 8, 165 | backgroundColor: 'white', 166 | }, 167 | inputWrap: { 168 | flex: 0.5, 169 | justifyContent: 'center', 170 | backgroundColor: 'white', 171 | padding: 20, 172 | }, 173 | }); 174 | 175 | export default CommentModal; 176 | -------------------------------------------------------------------------------- /src/animations/EventCard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | Animated, 6 | Linking, 7 | Text, 8 | Image, 9 | TouchableOpacity, 10 | ScrollView, 11 | } from 'react-native'; 12 | 13 | import BackIcon from '../icons/BackIcon'; 14 | import OpenIcon from '../icons/OpenIcon'; 15 | 16 | import Unsplash from './assets/images/4.jpeg'; 17 | 18 | class EventCard extends Component { 19 | static navigationOptions = ({ navigation }) => ({ 20 | headerTitle: 'Event Card', 21 | headerStyle: { 22 | height: 80, 23 | backgroundColor: '#EC407A', 24 | justifyContent: 'center', 25 | }, 26 | headerTitleStyle: { 27 | color: 'white', 28 | fontSize: 20, 29 | fontWeight: '400', 30 | }, 31 | headerLeft: navigation.goBack()} />, 32 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/EventCard.js')} />, 33 | }) 34 | 35 | state = { 36 | open: false, 37 | } 38 | 39 | componentWillMount() { 40 | this.animated = new Animated.Value(0); 41 | } 42 | 43 | toggleCard = () => { 44 | this.setState((state) => ({ 45 | open: !state.open, 46 | }), () => { 47 | const toValue = this.state.open ? 1 : 0; 48 | Animated.timing(this.animated, { 49 | toValue, 50 | duration: 500, 51 | }).start(); 52 | }); 53 | } 54 | 55 | render() { 56 | const offsetInterplate = this.animated.interpolate({ 57 | inputRange: [0, 1], 58 | outputRange: [191, 0], 59 | }); 60 | 61 | const arrowRotate = this.animated.interpolate({ 62 | inputRange: [0, 1], 63 | outputRange: ['180deg', '0deg'], 64 | }); 65 | 66 | const offsetStyle = { 67 | transform: [ 68 | { 69 | translateY: offsetInterplate, 70 | }, 71 | ], 72 | }; 73 | 74 | const arrowStyle = { 75 | transform: [ 76 | { 77 | rotate: arrowRotate, 78 | }, 79 | ], 80 | }; 81 | 82 | const opacityStyle = { 83 | opacity: this.animated, 84 | }; 85 | 86 | return ( 87 | 88 | 89 | 90 | 91 | 92 | 93 | Lets Get It On 94 | Marvin Gaye 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Don't you know how sweet and wonderful life can be? 105 | I'm askin' you baby to get it on with me, oh oh 106 | I ain't gonna worry, I ain't gonna push 107 | I won't push you baby 108 | So come on, come on, come on, come on baby 109 | Stop beatin' round the bush, hey 110 | Let's get it on, let's get it on 111 | You know what I'm talkin' 'bout 112 | Come on baby, let your love come out 113 | If you believe in love 114 | Let's get it on, let's get it on baby 115 | This minute, oh yeah let's get it on 116 | Please, let's get it on 117 | I know you know what I been dreamin' of, don't you baby? 118 | My whole body makes that feelin' of love, I'm happy 119 | I ain't gonna worry, no I ain't gonna push 120 | I won't push you baby, woo 121 | 122 | 123 | 124 | 125 | 126 | 127 | ); 128 | } 129 | } 130 | 131 | const styles = StyleSheet.create({ 132 | container: { 133 | flex: 1, 134 | justifyContent: 'center', 135 | alignItems: 'center', 136 | }, 137 | background: { 138 | width: 300, 139 | height: 250, 140 | borderRadius: 3, 141 | overflow: 'hidden', 142 | borderWidth: 3, 143 | borderColor: 'white', 144 | }, 145 | scrollViewWrap: { 146 | flex: 1, 147 | paddingTop: 5, 148 | }, 149 | contentText: { 150 | fontSize: 16, 151 | color: 'rgba(0,0,0,.5)', 152 | }, 153 | card: { 154 | backgroundColor: '#fff', 155 | flex: 1, 156 | paddingHorizontal: 15, 157 | paddingVertical: 4, 158 | transform: [{ 159 | translateY: 191, 160 | }], 161 | }, 162 | scrollView: { 163 | marginTop: 15, 164 | }, 165 | header: { 166 | flexDirection: 'row', 167 | }, 168 | title: { 169 | fontSize: 23, 170 | color: '#F06292', 171 | }, 172 | description: { 173 | fontSize: 17, 174 | color: '#F48FB1', 175 | }, 176 | arrowContainer: { 177 | flex: 1, 178 | alignItems: 'flex-end', 179 | justifyContent: 'center', 180 | }, 181 | arrow: { 182 | fontSize: 18, 183 | color: '#F48FB1', 184 | }, 185 | }); 186 | 187 | export default EventCard; 188 | -------------------------------------------------------------------------------- /src/animations/FloatingHeart.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | Animated, 6 | TouchableWithoutFeedback, 7 | Linking, 8 | Text, 9 | Dimensions, 10 | } from 'react-native'; 11 | 12 | import BackIcon from '../icons/BackIcon'; 13 | import OpenIcon from '../icons/OpenIcon'; 14 | 15 | const { width, height } = Dimensions.get('window'); 16 | 17 | const getRandomInt = (min, max) => { 18 | min = Math.ceil(min); 19 | max = Math.floor(max); 20 | return Math.floor(Math.random() * (max - min)) + min; // The maximum is exclusive and the minimum is inclusive 21 | }; 22 | 23 | class FloatingHeart extends Component { 24 | static navigationOptions = ({ navigation }) => ({ 25 | headerTitle: 'Floating Heart', 26 | headerStyle: { 27 | height: 80, 28 | backgroundColor: '#EC407A', 29 | justifyContent: 'center', 30 | }, 31 | headerTitleStyle: { 32 | color: 'white', 33 | fontSize: 20, 34 | fontWeight: '400', 35 | }, 36 | headerLeft: navigation.goBack()} />, 37 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/FloatingHeart.js')} />, 38 | }) 39 | 40 | state = { 41 | hearts: [], 42 | } 43 | 44 | handleAddHeart = () => { 45 | const animation = new Animated.Value(0); 46 | this.setState((state) => ({ 47 | hearts: [ 48 | ...state.hearts, 49 | { 50 | animation, 51 | start: getRandomInt(100, width - 100), 52 | }, 53 | ], 54 | }), () => { 55 | Animated.timing(animation, { 56 | toValue: height, 57 | duration: 3000, 58 | }).start(); 59 | }); 60 | } 61 | 62 | render() { 63 | return ( 64 | 65 | touch touch 66 | 67 | 68 | { 69 | this.state.hearts.map(({ animation, start }, index) => { 70 | const positionInterpolate = animation.interpolate({ 71 | inputRange: [0, height], 72 | outputRange: [height - 50, 0], 73 | }); 74 | 75 | const opacityInterpolate = animation.interpolate({ 76 | inputRange: [0, height - 200], 77 | outputRange: [1, 0], 78 | }); 79 | 80 | const scaleInterpolate = animation.interpolate({ 81 | inputRange: [0, 15, 30], 82 | outputRange: [0, 1.2, 1], 83 | extrapolate: 'clamp', 84 | }); 85 | 86 | const dividedHeight = height / 6; 87 | const wobbleInterpolate = animation.interpolate({ 88 | inputRange: [ 89 | 0, 90 | dividedHeight * 1, 91 | dividedHeight * 2, 92 | dividedHeight * 3, 93 | dividedHeight * 4, 94 | dividedHeight * 5, 95 | dividedHeight * 6, 96 | ], 97 | outputRange: [ 98 | 0, 99 | 15, 100 | -15, 101 | 15, 102 | -15, 103 | 15, 104 | -15, 105 | ], 106 | extrapolate: 'clamp', 107 | }); 108 | 109 | const heartStyle = { 110 | left: start, 111 | transform: [ 112 | { translateY: positionInterpolate }, 113 | { translateX: wobbleInterpolate }, 114 | { scale: scaleInterpolate }, 115 | ], 116 | opacity: opacityInterpolate, 117 | }; 118 | return ; 119 | }) 120 | } 121 | 122 | 123 | 124 | ); 125 | } 126 | } 127 | 128 | const Heart = ({ style }) => ( 129 | 130 | 131 | 132 | 133 | ); 134 | 135 | const styles = StyleSheet.create({ 136 | container: { 137 | flex: 1, 138 | alignItems: 'center', 139 | justifyContent: 'center', 140 | }, 141 | title: { 142 | color: '#F8BBD0', 143 | backgroundColor: 'transparent', 144 | fontSize: 30, 145 | }, 146 | heart: { 147 | width: 50, 148 | height: 50, 149 | position: 'absolute', 150 | }, 151 | heartShape: { 152 | width: 30, 153 | height: 45, 154 | position: 'absolute', 155 | top: 0, 156 | borderTopLeftRadius: 15, 157 | borderTopRightRadius: 15, 158 | backgroundColor: '#E91E63', 159 | }, 160 | leftHeart: { 161 | transform: [{ rotate: '-45deg' }], 162 | left: 5, 163 | }, 164 | rightHeart: { 165 | transform: [{ rotate: '45deg' }], 166 | right: 5, 167 | }, 168 | }); 169 | 170 | export default FloatingHeart; 171 | -------------------------------------------------------------------------------- /src/animations/MagicButton.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Text, 5 | TouchableWithoutFeedback, 6 | Animated, 7 | StyleSheet, 8 | Linking, 9 | } from 'react-native'; 10 | 11 | import BackIcon from '../icons/BackIcon'; 12 | import OpenIcon from '../icons/OpenIcon'; 13 | 14 | class MagicButton extends Component { 15 | static navigationOptions = ({ navigation }) => ({ 16 | headerTitle: 'Magic Button', 17 | headerStyle: { 18 | height: 80, 19 | backgroundColor: '#EC407A', 20 | justifyContent: 'center', 21 | }, 22 | headerTitleStyle: { 23 | color: 'white', 24 | fontSize: 20, 25 | fontWeight: '400', 26 | }, 27 | headerLeft: navigation.goBack()} />, 28 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/MagicButton.js')} />, 29 | }) 30 | 31 | constructor(props) { 32 | super(props); 33 | 34 | this.handlePressIn = this.handlePressIn.bind(this); 35 | this.handlePressOut = this.handlePressOut.bind(this); 36 | } 37 | 38 | componentWillMount() { 39 | this.animatedValue = new Animated.Value(1); 40 | } 41 | 42 | handlePressIn() { 43 | Animated.spring(this.animatedValue, { 44 | toValue: 0.5, 45 | }).start(); 46 | } 47 | 48 | handlePressOut() { 49 | Animated.spring(this.animatedValue, { 50 | toValue: 1, 51 | friction: 3, 52 | tension: 40, 53 | }).start(); 54 | } 55 | 56 | render() { 57 | const animatedStyle = { 58 | transform: [{ scale: this.animatedValue }], 59 | }; 60 | 61 | return ( 62 | 63 | 67 | 68 | Press Me 69 | 70 | 71 | 72 | ); 73 | } 74 | } 75 | 76 | const styles = StyleSheet.create({ 77 | container: { 78 | flex: 1, 79 | justifyContent: 'center', 80 | alignItems: 'center', 81 | }, 82 | button: { 83 | backgroundColor: '#9C27B0', 84 | width: 100, 85 | height: 50, 86 | alignItems: 'center', 87 | justifyContent: 'center', 88 | borderRadius: 5, 89 | }, 90 | text: { 91 | color: '#fff', 92 | }, 93 | }); 94 | 95 | export default MagicButton; 96 | -------------------------------------------------------------------------------- /src/animations/MagicCard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | Text, 4 | View, 5 | Animated, 6 | PanResponder, 7 | StyleSheet, 8 | Linking, 9 | } from 'react-native'; 10 | 11 | import BackIcon from '../icons/BackIcon'; 12 | import OpenIcon from '../icons/OpenIcon'; 13 | 14 | class MagicCard extends Component { 15 | static navigationOptions = ({ navigation }) => ({ 16 | headerTitle: 'Magic Card', 17 | headerStyle: { 18 | height: 80, 19 | backgroundColor: '#EC407A', 20 | justifyContent: 'center', 21 | }, 22 | headerTitleStyle: { 23 | color: 'white', 24 | fontSize: 20, 25 | fontWeight: '400', 26 | }, 27 | headerLeft: navigation.goBack()} />, 28 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/MagicCard.js')} />, 29 | }) 30 | 31 | componentWillMount() { 32 | this.animatedValue = new Animated.ValueXY(); 33 | this._value = { x: 0, y: 0 }; 34 | this.animatedValue.addListener((value) => this._value = value); // eslint-disable-line 35 | this.panResponder = PanResponder.create({ 36 | onStartShouldSetPanResponder: (evt, gestureState) => true, // eslint-disable-line 37 | onMoveShouldSetPanResponder: (evt, gestureState) => true, // eslint-disable-line 38 | onPanResponderGrant: (e, gestureState) => { // eslint-disable-line 39 | this.animatedValue.setOffset({ 40 | x: this._value.x, 41 | y: this._value.y, 42 | }); 43 | this.animatedValue.setValue({ x: 0, y: 0 }); 44 | }, 45 | onPanResponderMove: Animated.event([ 46 | null, 47 | { dx: this.animatedValue.x, dy: this.animatedValue.y }, 48 | ]), 49 | onPanResponderRelease: (e, gestureState) => { 50 | this.animatedValue.flattenOffset(); 51 | Animated.decay(this.animatedValue, { 52 | deceleration: 0.997, 53 | velocity: { x: gestureState.vx, y: gestureState.vy }, 54 | }).start(); 55 | }, 56 | }); 57 | } 58 | render() { 59 | const animatedStyle = { 60 | transform: this.animatedValue.getTranslateTransform(), 61 | }; 62 | return ( 63 | 64 | 65 | Drag Me 66 | 67 | 68 | ); 69 | } 70 | } 71 | 72 | const styles = StyleSheet.create({ 73 | container: { 74 | flex: 1, 75 | justifyContent: 'center', 76 | alignItems: 'center', 77 | }, 78 | box: { 79 | backgroundColor: '#D81B60', 80 | width: 100, 81 | height: 100, 82 | justifyContent: 'center', 83 | alignItems: 'center', 84 | }, 85 | text: { 86 | color: '#fff', 87 | }, 88 | }); 89 | 90 | export default MagicCard; 91 | -------------------------------------------------------------------------------- /src/animations/MagicInput.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | Text, 4 | View, 5 | Animated, 6 | TouchableWithoutFeedback, 7 | TouchableOpacity, 8 | TextInput, 9 | StyleSheet, 10 | Linking, 11 | } from 'react-native'; 12 | 13 | import BackIcon from '../icons/BackIcon'; 14 | import OpenIcon from '../icons/OpenIcon'; 15 | 16 | class MagicInput extends Component { 17 | static navigationOptions = ({ navigation }) => ({ 18 | headerTitle: 'Magic Input', 19 | headerStyle: { 20 | height: 80, 21 | backgroundColor: '#EC407A', 22 | justifyContent: 'center', 23 | }, 24 | headerTitleStyle: { 25 | color: 'white', 26 | fontSize: 20, 27 | fontWeight: '400', 28 | }, 29 | headerLeft: navigation.goBack()} />, 30 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/MagicInput.js')} />, 31 | }) 32 | 33 | state = { 34 | animated: new Animated.Value(0), 35 | success: false, 36 | } 37 | 38 | handlePress = () => { 39 | Animated.timing(this.state.animated, { 40 | toValue: 1, 41 | duration: 300, 42 | }).start(); 43 | } 44 | 45 | handleSend = () => { 46 | this.setState({ 47 | success: true, 48 | }, () => { 49 | Animated.sequence([ 50 | Animated.timing(this.state.animated, { 51 | toValue: 0, 52 | duration: 300, 53 | }), 54 | Animated.delay(1500), 55 | ]).start(() => this.setState({ success: false })); 56 | }); 57 | } 58 | 59 | render() { 60 | const widthInterpolate = this.state.animated.interpolate({ 61 | inputRange: [0, 0.5, 1], 62 | outputRange: [150, 150, 300], 63 | extrapolate: 'clamp', 64 | }); 65 | 66 | const inputScaleInterpolate = this.state.animated.interpolate({ 67 | inputRange: [0, 0.5, 0.6], 68 | outputRange: [0, 0, 1], 69 | extrapolate: 'clamp', 70 | }); 71 | 72 | const sendButtonInterpolate = this.state.animated.interpolate({ 73 | inputRange: [0, 0.6, 1], 74 | outputRange: [0, 0, 1], 75 | }); 76 | 77 | const notifyTextScaleInterpolate = this.state.animated.interpolate({ 78 | inputRange: [0, 0.5], 79 | outputRange: [1, 0], 80 | extrapolate: 'clamp', 81 | }); 82 | 83 | const thankyouScaleInterpolate = this.state.animated.interpolate({ 84 | inputRange: [0, 1], 85 | outputRange: [1, 0], 86 | }); 87 | 88 | const thankYouTextStyle = { 89 | transform: [ 90 | { 91 | scale: thankyouScaleInterpolate, 92 | }, 93 | ], 94 | }; 95 | 96 | const inputScaleStyle = { 97 | transform: [ 98 | { scale: inputScaleInterpolate }, 99 | ], 100 | }; 101 | 102 | const buttonWrapStyle = { 103 | width: widthInterpolate, 104 | }; 105 | 106 | const sendButtonStyle = { 107 | transform: [ 108 | { scale: sendButtonInterpolate }, 109 | ], 110 | }; 111 | 112 | const notifyTextStyle = { 113 | transform: [ 114 | { scale: notifyTextScaleInterpolate }, 115 | ], 116 | }; 117 | 118 | const { animated, success } = this.state; 119 | 120 | return ( 121 | 122 | 123 | 124 | {!success && 125 | 126 | 134 | 135 | Send 136 | 137 | 138 | } 139 | 140 | {!success && 141 | Notify Me 142 | } 143 | {success && 144 | Thank You 145 | } 146 | 147 | 148 | 149 | ); 150 | } 151 | } 152 | 153 | const styles = StyleSheet.create({ 154 | container: { 155 | flex: 1, 156 | justifyContent: 'center', 157 | alignItems: 'center', 158 | backgroundColor: '#F06292', 159 | }, 160 | touchWF: { 161 | borderRadius: 25, 162 | }, 163 | buttonWrap: { 164 | position: 'absolute', 165 | height: 50, 166 | backgroundColor: 'white', 167 | borderRadius: 25, 168 | }, 169 | sendContainer: { 170 | flex: 1, 171 | position: 'absolute', 172 | justifyContent: 'flex-start', 173 | alignItems: 'center', 174 | flexDirection: 'row', 175 | }, 176 | textInput: { 177 | left: 10, 178 | width: 212, 179 | fontSize: 16, 180 | color: '#F06292', 181 | }, 182 | placeholderText: { 183 | fontSize: 16, 184 | color: '#F06292', 185 | }, 186 | sendButton: { 187 | width: 80, 188 | height: 44, 189 | borderRadius: 22, 190 | backgroundColor: '#F06292', 191 | }, 192 | center: { 193 | alignItems: 'center', 194 | justifyContent: 'center', 195 | }, 196 | sendText: { 197 | color: 'white', 198 | backgroundColor: 'transparent', 199 | fontSize: 16, 200 | }, 201 | notifyText: { 202 | position: 'absolute', 203 | color: '#F06292', 204 | fontWeight: '700', 205 | backgroundColor: 'transparent', 206 | }, 207 | }); 208 | 209 | export default MagicInput; 210 | -------------------------------------------------------------------------------- /src/animations/ParallaxScrollview.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Animated, 5 | StyleSheet, 6 | ScrollView, 7 | Dimensions, 8 | Linking, 9 | } from 'react-native'; 10 | 11 | import BackIcon from '../icons/BackIcon'; 12 | import OpenIcon from '../icons/OpenIcon'; 13 | import Moment from './components/moment'; 14 | 15 | const { width, height } = Dimensions.get('window'); 16 | 17 | const Images = [ 18 | { 19 | title: 'Saling', 20 | image: require('./assets/images/1.jpeg'), 21 | }, { 22 | title: 'Lets Get It On', 23 | image: require('./assets/images/2.jpg'), 24 | }, { 25 | title: 'All Right', 26 | image: require('./assets/images/3.jpeg'), 27 | }, { 28 | title: 'Viva La Vida', 29 | image: require('./assets/images/4.jpeg'), 30 | }, 31 | ]; 32 | 33 | const getInterpolate = (animatedScroll, i, imageLength) => { 34 | const inputRange = [ 35 | (i - 1) * width, 36 | i * width, 37 | (i + 1) * width, 38 | ]; 39 | 40 | const outputRange = i === 0 ? [0, 0, 150] : [-300, 0, 150]; 41 | return animatedScroll.interpolate({ 42 | inputRange, 43 | outputRange, 44 | extrapolate: 'clamp', 45 | }); 46 | }; 47 | 48 | const getSeparator = (i) => (); 52 | 53 | class ParallaxScrollview extends Component { 54 | static navigationOptions = ({ navigation }) => ({ 55 | headerTitle: 'Magic Card', 56 | headerStyle: { 57 | height: 80, 58 | backgroundColor: '#EC407A', 59 | justifyContent: 'center', 60 | }, 61 | headerTitleStyle: { 62 | color: 'white', 63 | fontSize: 20, 64 | fontWeight: '400', 65 | }, 66 | headerLeft: navigation.goBack()} />, 67 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/ParallaxScrollview.js')} />, 68 | }) 69 | 70 | constructor(props) { 71 | super(props); 72 | this.state = { 73 | animatedScroll: new Animated.Value(0), 74 | scrollEnabled: true, 75 | }; 76 | } 77 | 78 | handleFocus = (focused) => { 79 | this.setState({ 80 | scrollEnabled: !focused, 81 | }); 82 | } 83 | 84 | render() { 85 | return ( 86 | 87 | 104 | {Images.map((image, i) => ( 105 | 112 | ))} 113 | {Array(...{ length: Images.length + 1 }).map((_, i) => getSeparator(i))} 114 | 115 | 116 | ); 117 | } 118 | } 119 | 120 | const styles = StyleSheet.create({ 121 | container: { 122 | height, 123 | width, 124 | overflow: 'hidden', 125 | }, 126 | separate: { 127 | backgroundColor: 'black', 128 | position: 'absolute', 129 | top: 0, 130 | bottom: 0, 131 | width: 5, 132 | }, 133 | }); 134 | 135 | export default ParallaxScrollview; 136 | -------------------------------------------------------------------------------- /src/animations/SpringyMenu.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | StyleSheet, 5 | Linking, 6 | Animated, 7 | TouchableOpacity, 8 | Text, 9 | } from 'react-native'; 10 | 11 | import BackIcon from '../icons/BackIcon'; 12 | import OpenIcon from '../icons/OpenIcon'; 13 | 14 | const getTransformStyle = (animation) => ({ 15 | transform: [ 16 | { translateY: animation }, 17 | ], 18 | }); 19 | 20 | class SpringyMenu extends Component { 21 | static navigationOptions = ({ navigation }) => ({ 22 | headerTitle: 'Springy Menu', 23 | headerStyle: { 24 | height: 80, 25 | backgroundColor: '#EC407A', 26 | justifyContent: 'center', 27 | }, 28 | headerTitleStyle: { 29 | color: 'white', 30 | fontSize: 20, 31 | fontWeight: '400', 32 | }, 33 | headerLeft: navigation.goBack()} />, 34 | headerRight: Linking.openURL('https://github.com/bkdev98/react-native-animation-examples/blob/master/src/animations/SpringyMenu.js')} />, 35 | }) 36 | 37 | constructor(props) { 38 | super(props); 39 | this.state = { 40 | animate: new Animated.Value(0), 41 | fabs: [ 42 | new Animated.Value(0), 43 | new Animated.Value(0), 44 | new Animated.Value(0), 45 | ], 46 | }; 47 | this.open = false; 48 | } 49 | 50 | handlePress = () => { 51 | const toValue = this.open ? 0 : 1; 52 | const flyouts = this.state.fabs.map((value, i) => Animated.spring(value, { 53 | toValue: (i + 1) * -90 * toValue, 54 | friction: 5, 55 | })); 56 | 57 | Animated.parallel([ 58 | Animated.timing(this.state.animate, { 59 | toValue, 60 | duration: 300, 61 | }), 62 | Animated.stagger(30, flyouts), 63 | ]).start(); 64 | this.open = !this.open; 65 | } 66 | 67 | render() { 68 | const backgroundInterpolate = this.state.animate.interpolate({ 69 | inputRange: [0, 1], 70 | outputRange: ['rgb(90,34,153)', 'rgb(36,11,63)'], 71 | }); 72 | 73 | const backgroundStyle = { 74 | backgroundColor: backgroundInterpolate, 75 | }; 76 | 77 | const buttonColorInterpolate = this.state.animate.interpolate({ 78 | inputRange: [0, 1], 79 | outputRange: ['rgb(24,214,255)', 'rgb(255,255,255)'], 80 | }); 81 | 82 | const buttonRotate = this.state.animate.interpolate({ 83 | inputRange: [0, 1], 84 | outputRange: ['0deg', '135deg'], 85 | }); 86 | 87 | const buttonStyle = { 88 | backgroundColor: buttonColorInterpolate, 89 | transform: [ 90 | { rotate: buttonRotate }, 91 | ], 92 | }; 93 | 94 | return ( 95 | 96 | 97 | 98 | { 99 | this.state.fabs.map((animation, i) => ( 100 | 105 | )) 106 | } 107 | 108 | 109 | + 110 | 111 | 112 | 113 | 114 | 115 | ); 116 | } 117 | } 118 | 119 | const styles = StyleSheet.create({ 120 | container: { 121 | flex: 1, 122 | justifyContent: 'center', 123 | alignItems: 'center', 124 | }, 125 | menuContainer: { 126 | flex: 1, 127 | }, 128 | position: { 129 | position: 'absolute', 130 | right: 45, 131 | bottom: 45, 132 | }, 133 | fab: { 134 | position: 'absolute', 135 | bottom: 0, 136 | right: 0, 137 | }, 138 | button: { 139 | width: 80, 140 | height: 80, 141 | borderRadius: 40, 142 | alignItems: 'center', 143 | justifyContent: 'center', 144 | }, 145 | flyout: { 146 | backgroundColor: '#9439FF', 147 | }, 148 | plus: { 149 | fontWeight: 'bold', 150 | fontSize: 30, 151 | color: '#00768F', 152 | }, 153 | }); 154 | 155 | export default SpringyMenu; 156 | -------------------------------------------------------------------------------- /src/animations/assets/images/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/src/animations/assets/images/1.jpeg -------------------------------------------------------------------------------- /src/animations/assets/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/src/animations/assets/images/2.jpg -------------------------------------------------------------------------------- /src/animations/assets/images/3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/src/animations/assets/images/3.jpeg -------------------------------------------------------------------------------- /src/animations/assets/images/4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/src/animations/assets/images/4.jpeg -------------------------------------------------------------------------------- /src/animations/assets/images/beansable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bkdev98/react-native-animation-examples/2ee8721f771cb4ab1872d5a29828d8bc916fb41d/src/animations/assets/images/beansable.png -------------------------------------------------------------------------------- /src/animations/components/heart.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, StyleSheet, Animated } from 'react-native'; 3 | 4 | const Heart = ({ filled, style, ...props }) => { 5 | const centerNonFilled = ( 6 | 7 | 8 | 9 | 10 | ); 11 | const fillStyle = filled ? styles.filledHeart : styles.empty; 12 | return ( 13 | 14 | 15 | 16 | {!filled && centerNonFilled} 17 | 18 | ); 19 | }; 20 | 21 | const styles = StyleSheet.create({ 22 | heart: { 23 | width: 50, 24 | height: 50, 25 | backgroundColor: 'transparent', 26 | }, 27 | heartShape: { 28 | width: 30, 29 | height: 45, 30 | position: 'absolute', 31 | top: 0, 32 | borderTopLeftRadius: 15, 33 | borderTopRightRadius: 15, 34 | }, 35 | filledHeart: { 36 | backgroundColor: '#EC407A', 37 | }, 38 | fit: { 39 | transform: [ 40 | { scale: 0.9 }, 41 | ], 42 | }, 43 | emptyFill: { 44 | backgroundColor: '#FFF', 45 | }, 46 | empty: { 47 | backgroundColor: '#CCC', 48 | }, 49 | leftHeart: { 50 | transform: [ 51 | { rotate: '-45deg' }, 52 | ], 53 | left: 5, 54 | }, 55 | rightHeart: { 56 | transform: [ 57 | { rotate: '45deg' }, 58 | ], 59 | right: 5, 60 | }, 61 | }); 62 | 63 | export default Heart; 64 | -------------------------------------------------------------------------------- /src/animations/components/moment.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Text, 5 | StyleSheet, 6 | Animated, 7 | Dimensions, 8 | TouchableWithoutFeedback, 9 | } from 'react-native'; 10 | 11 | const { width, height } = Dimensions.get('window'); 12 | 13 | class Moment extends Component { 14 | state = { 15 | scale: new Animated.Value(1), 16 | } 17 | 18 | componentWillMount() { 19 | this.bgFadeInterpolate = this.state.scale.interpolate({ 20 | inputRange: [0.9, 1], 21 | outputRange: ['rgba(0,0,0,.3)', 'rgba(0,0,0,0)'], 22 | }); 23 | this.textFade = this.state.scale.interpolate({ 24 | inputRange: [0.9, 1], 25 | outputRange: [0, 1], 26 | }); 27 | this.calloutTranslate = this.state.scale.interpolate({ 28 | inputRange: [0.9, 1], 29 | outputRange: [0, 150], 30 | }); 31 | } 32 | 33 | handlePress = () => { 34 | if (this.props.focused) { 35 | Animated.timing(this.state.scale, { 36 | toValue: 1, 37 | duration: 300, 38 | }).start(() => this.props.onFocus(false)); 39 | return; 40 | } 41 | Animated.timing(this.state.scale, { 42 | toValue: 0.9, 43 | duration: 300, 44 | }).start(() => this.props.onFocus(true)); 45 | } 46 | 47 | render() { 48 | const animatedStyle = { 49 | transform: [ 50 | { translateX: this.props.translateX }, 51 | { scale: this.state.scale }, 52 | ], 53 | }; 54 | 55 | const bgFadeStyle = { 56 | backgroundColor: this.bgFadeInterpolate, 57 | }; 58 | 59 | const textFadeStyle = { 60 | opacity: this.textFade, 61 | }; 62 | 63 | const calloutStyle = { 64 | transform: [{ 65 | translateY: this.calloutTranslate, 66 | }], 67 | }; 68 | 69 | return ( 70 | 71 | 76 | 77 | 78 | 79 | {this.props.title} 80 | 81 | 82 | 83 | 84 | 85 | {this.props.title} 86 | 87 | 88 | 89 | ); 90 | } 91 | } 92 | 93 | const styles = StyleSheet.create({ 94 | container: { 95 | width, 96 | height, 97 | overflow: 'hidden', 98 | }, 99 | image: { 100 | flex: 1, 101 | width: null, 102 | height: null, 103 | }, 104 | center: { 105 | justifyContent: 'center', 106 | }, 107 | textWrap: { 108 | backgroundColor: 'rgba(0,0,0,.5)', 109 | paddingVertical: 10, 110 | }, 111 | title: { 112 | backgroundColor: 'transparent', 113 | fontSize: 30, 114 | color: 'white', 115 | textAlign: 'center', 116 | }, 117 | callout: { 118 | height: 150, 119 | backgroundColor: 'rgba(0,0,0,.5)', 120 | position: 'absolute', 121 | bottom: 0, 122 | right: 0, 123 | left: 0, 124 | }, 125 | }); 126 | 127 | export default Moment; 128 | -------------------------------------------------------------------------------- /src/components/Info.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | View, 4 | Text, 5 | TouchableOpacity, 6 | TouchableWithoutFeedback, 7 | Animated, 8 | StyleSheet, 9 | Linking, 10 | Dimensions, 11 | } from 'react-native'; 12 | 13 | const { width, height } = Dimensions.get('window'); 14 | 15 | class Info extends Component { 16 | componentWillMount() { 17 | this.animate = new Animated.Value(0); 18 | } 19 | 20 | render() { 21 | return ( 22 | 23 | this.props.onPress()}> 24 | 25 | 26 | 27 | 28 | 29 | 30 | Animations Collection 31 | 32 | 33 | Created by Quoc Khanh 34 | & React Native 💖 35 | 36 | Linking.openURL('https://facebook.com/bkdev98')} 39 | > 40 | CONTACT 41 | 42 | 43 | 44 | 45 | ); 46 | } 47 | } 48 | 49 | const styles = StyleSheet.create({ 50 | container: { 51 | flex: 1, 52 | width, 53 | height: height * 0.8, 54 | alignItems: 'center', 55 | justifyContent: 'center', 56 | }, 57 | infoContainer: { 58 | // flex: 1, 59 | width: width * 0.8, 60 | height: 250, 61 | }, 62 | infoOverlay: { 63 | position: 'absolute', 64 | flex: 1, 65 | height, 66 | width, 67 | backgroundColor: 'rgba(0,0,0,.4)', 68 | }, 69 | titleContainer: { 70 | flex: 4, 71 | backgroundColor: '#F06292', 72 | alignItems: 'center', 73 | justifyContent: 'center', 74 | }, 75 | title: { 76 | fontSize: 24, 77 | color: 'white', 78 | }, 79 | contentContainer: { 80 | flex: 3, 81 | backgroundColor: 'white', 82 | alignItems: 'center', 83 | justifyContent: 'space-around', 84 | paddingVertical: 10, 85 | }, 86 | createdBy: { 87 | fontSize: 20, 88 | color: '#616161', 89 | }, 90 | description: { 91 | fontSize: 20, 92 | color: '#F06292', 93 | }, 94 | button: { 95 | flex: 3, 96 | backgroundColor: '#F8BBD0', 97 | alignItems: 'center', 98 | justifyContent: 'center', 99 | }, 100 | buttonText: { 101 | color: '#EC407A', 102 | fontSize: 17, 103 | letterSpacing: 1.4, 104 | fontWeight: 'bold', 105 | }, 106 | }); 107 | 108 | export default Info; 109 | -------------------------------------------------------------------------------- /src/components/List.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | FlatList, 4 | Text, 5 | View, 6 | TouchableOpacity, 7 | StyleSheet, 8 | StatusBar, 9 | Share, 10 | } from 'react-native'; 11 | 12 | import ShareIcon from '../icons/ShareIcon'; 13 | import HelpIcon from '../icons/HelpIcon'; 14 | import Info from './Info'; 15 | 16 | const data = [{ 17 | // key: 'AnimatedBasic', 18 | // title: 'Animated Basic', 19 | // }, { 20 | // key: 'MagicButton', 21 | // title: 'Magic Button', 22 | // }, { 23 | // key: 'MagicCard', 24 | // title: 'Magic Card', 25 | // }, { 26 | // key: 'ColorBox', 27 | // title: 'Color Box', 28 | // }, { 29 | key: 'ParallaxScrollview', 30 | title: 'Parallax Scrollview', 31 | icon: '🐬', 32 | }, { 33 | key: 'BouncingHeart', 34 | title: 'Bouncing Heart', 35 | icon: '💕', 36 | }, { 37 | key: 'SpringyMenu', 38 | title: 'Springy Menu', 39 | icon: '🍕', 40 | }, { 41 | key: 'CommentModal', 42 | title: 'Comment Modal', 43 | icon: '🍻', 44 | }, { 45 | key: 'FloatingHeart', 46 | title: 'Floating Heart', 47 | icon: '🦄', 48 | }, { 49 | key: 'EventCard', 50 | title: 'Event Card', 51 | icon: '🎼', 52 | }, { 53 | key: 'CollapseHeader', 54 | title: 'Collapse Header', 55 | icon: '🎃', 56 | }, { 57 | key: 'MagicInput', 58 | title: 'Magic Input', 59 | icon: '💅', 60 | }]; 61 | 62 | class List extends Component { 63 | static navigationOptions = ({ navigation }) => ({ 64 | headerTitle: 'Animations', 65 | headerStyle: { 66 | height: 80, 67 | backgroundColor: '#EC407A', 68 | justifyContent: 'center', 69 | }, 70 | headerTitleStyle: { 71 | color: 'white', 72 | fontSize: 20, 73 | fontWeight: '400', 74 | }, 75 | headerRight: Share.share({ 76 | message: 'Well its not far down to paradise, at leasts not for me', 77 | title: 'Christopher Cross', 78 | url: 'https://github.com/bkdev98/react-native-animation-examples', 79 | }, { 80 | dialogTitle: 'Sailing', 81 | })} 82 | />, 83 | headerLeft: navigation.state.params ? navigation.state.params.headerLeft : null, 84 | }) 85 | 86 | state = { 87 | infoOpen: false, 88 | } 89 | 90 | componentDidMount() { 91 | this.props.navigation.setParams({ 92 | headerLeft: , 93 | }); 94 | } 95 | 96 | toggleInfoDialog = () => { 97 | this.setState({ 98 | infoOpen: !this.state.infoOpen, 99 | }); 100 | } 101 | 102 | render() { 103 | return ( 104 | 105 | {this.state.infoOpen && 106 | 107 | this.setState({ infoOpen: true })} /> 108 | 109 | } 110 | 111 | 112 | 115 | ( this.props.navigation.navigate(item.key)} 117 | style={[styles.itemContainer, { backgroundColor: `rgba(255, 26, 117, ${0.3 + (0.05 * index)})` }]} 118 | > 119 | 120 | {item.icon} 121 | 122 | 123 | {item.title} 124 | 125 | ) 126 | } 127 | /> 128 | 129 | ); 130 | } 131 | } 132 | 133 | const styles = StyleSheet.create({ 134 | container: { 135 | flex: 1, 136 | }, 137 | infoContainer: { 138 | position: 'absolute', 139 | zIndex: 1000, 140 | }, 141 | headerContainer: { 142 | height: 100, 143 | backgroundColor: '#EC407A', 144 | justifyContent: 'center', 145 | alignItems: 'center', 146 | }, 147 | headerTitle: { 148 | color: 'white', 149 | fontSize: 25, 150 | }, 151 | itemContainer: { 152 | flexDirection: 'row', 153 | height: 90, 154 | }, 155 | iconContainer: { 156 | width: 90, 157 | backgroundColor: 'rgba(255,255,255,.1)', 158 | justifyContent: 'center', 159 | alignItems: 'center', 160 | }, 161 | icon: { 162 | fontSize: 30, 163 | }, 164 | itemTitleContainer: { 165 | justifyContent: 'center', 166 | paddingLeft: 20, 167 | }, 168 | itemTitle: { 169 | color: 'white', 170 | fontSize: 20, 171 | }, 172 | }); 173 | 174 | export default List; 175 | -------------------------------------------------------------------------------- /src/components/StatusBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Platform, View } from 'react-native'; 3 | 4 | const StatusBar = () => ( 5 | Platform.OS === 'android' && Platform.Version >= 20 ? 6 | 7 | : 8 | ); 9 | 10 | export default StatusBar; 11 | -------------------------------------------------------------------------------- /src/icons/BackIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | 5 | const BackIcon = ({ onPress }) => ( 6 | 15 | 16 | 17 | ); 18 | 19 | export default BackIcon; 20 | -------------------------------------------------------------------------------- /src/icons/HelpIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | 5 | const ShareIcon = ({ onPress }) => ( 6 | 15 | 16 | 17 | ); 18 | 19 | export default ShareIcon; 20 | -------------------------------------------------------------------------------- /src/icons/MenuIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | 5 | const ShareIcon = ({ onPress }) => ( 6 | 15 | 16 | 17 | ); 18 | 19 | export default ShareIcon; 20 | -------------------------------------------------------------------------------- /src/icons/OpenIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | 5 | const OpenIcon = ({ onPress }) => ( 6 | 14 | 15 | 16 | ); 17 | 18 | export default OpenIcon; 19 | -------------------------------------------------------------------------------- /src/icons/ShareIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import Ionicons from '@expo/vector-icons/Ionicons'; 4 | 5 | const ShareIcon = ({ onPress }) => ( 6 | 14 | 15 | 16 | ); 17 | 18 | export default ShareIcon; 19 | --------------------------------------------------------------------------------