├── .watchmanconfig ├── .gitignore ├── app.json ├── .DS_Store ├── demo2.gif ├── assets ├── .DS_Store ├── dublin.jpg ├── seville.jpg ├── venice.jpg ├── amsterdam.jpg ├── dublinAvatar.png ├── veniceAvatar.jpg ├── amsterdamAvatar.jpg └── sevilleAvatar.jpg ├── ParallexSwiper ├── index.js ├── styles.js └── ParallexSwiper.js ├── .babelrc ├── App.test.js ├── App.js ├── package.json ├── README.md ├── data.js └── .flowconfig /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "sdkVersion": "21.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/.DS_Store -------------------------------------------------------------------------------- /demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/demo2.gif -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/.DS_Store -------------------------------------------------------------------------------- /assets/dublin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/dublin.jpg -------------------------------------------------------------------------------- /assets/seville.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/seville.jpg -------------------------------------------------------------------------------- /assets/venice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/venice.jpg -------------------------------------------------------------------------------- /assets/amsterdam.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/amsterdam.jpg -------------------------------------------------------------------------------- /assets/dublinAvatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/dublinAvatar.png -------------------------------------------------------------------------------- /assets/veniceAvatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/veniceAvatar.jpg -------------------------------------------------------------------------------- /ParallexSwiper/index.js: -------------------------------------------------------------------------------- 1 | import ParallexSwiper from './ParallexSwiper'; 2 | 3 | export default ParallexSwiper; 4 | -------------------------------------------------------------------------------- /assets/amsterdamAvatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/amsterdamAvatar.jpg -------------------------------------------------------------------------------- /assets/sevilleAvatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sankhadeeproy007/CardAnimation/HEAD/assets/sevilleAvatar.jpg -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["babel-preset-expo"], 3 | "env": { 4 | "development": { 5 | "plugins": ["transform-react-jsx-source"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import App from './App'; 3 | 4 | import renderer from 'react-test-renderer'; 5 | 6 | it('renders without crashing', () => { 7 | const rendered = renderer.create().toJSON(); 8 | expect(rendered).toBeTruthy(); 9 | }); 10 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, View } from 'react-native'; 3 | import ParallexSwiper from './ParallexSwiper'; 4 | import data from './data'; 5 | 6 | export default class App extends React.Component { 7 | render() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | } 15 | 16 | const styles = StyleSheet.create({ 17 | container: { 18 | paddingTop: 20, 19 | flex: 1, 20 | justifyContent: 'center', 21 | alignItems: 'center', 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CardAnimate", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "react-native-scripts": "1.5.0", 7 | "jest-expo": "^21.0.2", 8 | "react-test-renderer": "16.0.0-alpha.12" 9 | }, 10 | "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js", 11 | "scripts": { 12 | "start": "react-native-scripts start", 13 | "eject": "react-native-scripts eject", 14 | "android": "react-native-scripts android", 15 | "ios": "react-native-scripts ios", 16 | "test": "node node_modules/jest/bin/jest.js --watch" 17 | }, 18 | "jest": { 19 | "preset": "jest-expo" 20 | }, 21 | "dependencies": { 22 | "expo": "^21.0.0", 23 | "react": "16.0.0-alpha.12", 24 | "react-native": "^0.48.4" 25 | } 26 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ParallexSwiper in react-native! 2 | ![](https://github.com/sankhadeeproy007/CardAnimation/blob/master/demo2.gif) 3 | 4 | 5 | `` takes `data` as a prop (built on top of react-native FlatList). 6 | Shape of `data` object is 7 | ``` 8 | { 9 | name: '', 10 | cover: require(''), 11 | avatar: require(''), 12 | cardTitle: '', 13 | cardText: '', 14 | }, 15 | ``` 16 | `cover` and `avatar` are images. 17 | 18 | ## Example 19 | ``` 20 | import ParallexSwiper from './ParallexSwiper'; 21 | 22 | export default class App extends React.Component { 23 | render() { 24 | return ( 25 | 26 | ); 27 | } 28 | } 29 | ``` 30 | 31 | ### To-do 32 | * Make card configurable (support images) 33 | * Animated duration and easing functions as props 34 | 35 | 36 | _Laggy gif is due to low fps of gif recorder_ 37 | -------------------------------------------------------------------------------- /ParallexSwiper/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet, Dimensions } from 'react-native'; 2 | const { width, height } = Dimensions.get('window'); 3 | const styles = StyleSheet.create({ 4 | container: { 5 | paddingTop: 20, 6 | flex: 1, 7 | justifyContent: 'center', 8 | alignItems: 'center', 9 | }, 10 | item: { 11 | width: width, 12 | height: height, 13 | flex: 1, 14 | justifyContent: 'center', 15 | alignItems: 'center', 16 | }, 17 | touchableHeight: { 18 | height: height * 0.8, 19 | width: width * 0.8, 20 | borderRadius: 10, 21 | }, 22 | shadowContainer: { 23 | borderRadius: 10, 24 | shadowColor: '#000', 25 | shadowOffset: { 26 | width: 0, 27 | height: 3, 28 | }, 29 | shadowOpacity: 0.27, 30 | shadowRadius: 4.65, 31 | }, 32 | innerShadow: { 33 | height: '60%', 34 | overflow: 'hidden', 35 | borderTopRightRadius: 10, 36 | borderTopLeftRadius: 10, 37 | }, 38 | coverImage: { 39 | width: '100%', 40 | height: '100%', 41 | }, 42 | innerAnimated: { 43 | justifyContent: 'center', 44 | alignItems: 'center', 45 | marginTop: 20, 46 | }, 47 | avatar: { 48 | width: 80, 49 | height: 80, 50 | borderRadius: 40, 51 | }, 52 | title: { 53 | fontSize: 18, 54 | marginTop: 8, 55 | color: '#303030', 56 | }, 57 | animatedCard: { 58 | justifyContent: 'center', 59 | alignItems: 'center', 60 | alignSelf: 'center', 61 | backgroundColor: '#fff', 62 | height: 200, 63 | width: 375, 64 | }, 65 | innerCard: { 66 | borderRadius: 5, 67 | shadowColor: '#000', 68 | shadowOffset: { 69 | width: 0, 70 | height: 3, 71 | }, 72 | shadowOpacity: 0.27, 73 | shadowRadius: 4.65, 74 | height: 200, 75 | width: 220, 76 | }, 77 | cardTitle: { textAlign: 'center', marginTop: 12 }, 78 | cardText: { color: '#626262', fontSize: 12 }, 79 | cardPadding: { padding: 12 }, 80 | }); 81 | 82 | export default styles; 83 | -------------------------------------------------------------------------------- /data.js: -------------------------------------------------------------------------------- 1 | const data = [ 2 | { 3 | name: 'Venice', 4 | cover: require('./assets/venice.jpg'), 5 | avatar: require('./assets/veniceAvatar.jpg'), 6 | cardTitle: 'Venice', 7 | cardText: 8 | 'Venice, the capital of northern Italy’s Veneto region, is built on more than 100 small islands in a lagoon in the Adriatic Sea. It has no roads, just canals – including the Grand Canal thoroughfare – lined with Renaissance and Gothic palaces.', 9 | }, 10 | { 11 | name: 'Seville', 12 | cover: require('./assets/seville.jpg'), 13 | avatar: require('./assets/sevilleAvatar.jpg'), 14 | cardTitle: 'Seville', 15 | cardText: 16 | 'Seville is the capital of southern Spain’s Andalusia region. It is famous for flamenco dancing, particularly in its Triana neighborhood. Major landmarks include the ornate Alcázar castle complex, built during the Moorish Almohad dynasty, and the 18th-century Plaza de Toros de la Maestranza bullring.', 17 | }, 18 | { 19 | name: 'Amsterdam', 20 | cover: require('./assets/amsterdam.jpg'), 21 | avatar: require('./assets/amsterdamAvatar.jpg'), 22 | cardTitle: 'Amsterdam', 23 | cardText: 24 | 'Amsterdam is the Netherlands capital, known for its artistic heritage, elaborate canal system and narrow houses with gabled facades, legacies of the city’s 17th-century Golden Age. Its Museum District houses the Van Gogh Museum, works by Vermeer at the Rijksmuseum, and modern art at the Stedelijk.', 25 | }, 26 | { 27 | name: 'Dublin', 28 | cover: require('./assets/dublin.jpg'), 29 | avatar: require('./assets/dublinAvatar.png'), 30 | cardTitle: 'Dublin', 31 | cardText: 32 | 'Dublin, capital of the Republic of Ireland, is on Ireland’s east coast at the mouth of the River Liffey. Its historic buildings include Dublin Castle, dating to the 13th century, and imposing St Patrick’s Cathedral, founded in 1191. City parks include landscaped St Stephen’s Green and huge Phoenix Park.', 33 | }, 34 | ]; 35 | 36 | export default data; 37 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | ; Additional create-react-native-app ignores 18 | 19 | ; Ignore duplicate module providers 20 | .*/node_modules/fbemitter/lib/* 21 | 22 | ; Ignore misbehaving dev-dependencies 23 | .*/node_modules/xdl/build/* 24 | .*/node_modules/reqwest/tests/* 25 | 26 | ; Ignore missing expo-sdk dependencies (temporarily) 27 | ; https://github.com/expo/expo/issues/162 28 | .*/node_modules/expo/src/* 29 | 30 | ; Ignore react-native-fbads dependency of the expo sdk 31 | .*/node_modules/react-native-fbads/* 32 | 33 | [include] 34 | 35 | [libs] 36 | node_modules/react-native/Libraries/react-native/react-native-interface.js 37 | node_modules/react-native/flow 38 | flow/ 39 | 40 | [options] 41 | module.system=haste 42 | 43 | emoji=true 44 | 45 | experimental.strict_type_args=true 46 | 47 | munge_underscores=true 48 | 49 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 50 | 51 | suppress_type=$FlowIssue 52 | suppress_type=$FlowFixMe 53 | suppress_type=$FixMe 54 | 55 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 56 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 57 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 58 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 59 | 60 | unsafe.enable_getters_and_setters=true 61 | 62 | [version] 63 | ^0.49.1 64 | -------------------------------------------------------------------------------- /ParallexSwiper/ParallexSwiper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | FlatList, 7 | Dimensions, 8 | Animated, 9 | Image, 10 | TouchableOpacity, 11 | } from 'react-native'; 12 | import styles from './styles'; 13 | 14 | const { width, height } = Dimensions.get('window'); 15 | 16 | const AnimatedList = Animated.createAnimatedComponent(FlatList); 17 | 18 | const getInterpolate = (animatedScroll, i) => { 19 | const inputRange = [i - 1 * width, i * width, (i + 1) * width]; 20 | 21 | const outputRange = i === 0 ? [0, 0, 110] : [-300, 0, 110]; 22 | 23 | return animatedScroll.interpolate({ 24 | inputRange, 25 | outputRange, 26 | extrapolate: 'clamp', 27 | }); 28 | }; 29 | 30 | export default class App extends React.Component { 31 | constructor(props) { 32 | super(props); 33 | this.state = { 34 | currentPage: 0, 35 | scrollDisabled: false, 36 | }; 37 | } 38 | imageParallex = new Animated.Value(0); 39 | coverScale = new Animated.Value(0); 40 | animate() { 41 | if (!this.state.scrollDisabled) { 42 | Animated.timing(this.coverScale, { 43 | toValue: 1, 44 | duration: 300, 45 | useNativeDriver: true, 46 | }).start(); 47 | } else { 48 | Animated.timing(this.coverScale, { 49 | toValue: 0, 50 | duration: 300, 51 | useNativeDriver: true, 52 | }).start(); 53 | } 54 | this.setState({ 55 | scrollDisabled: !this.state.scrollDisabled, 56 | }); 57 | } 58 | opacity = this.coverScale.interpolate({ 59 | inputRange: [0, 0.5, 1], 60 | outputRange: [1, 0.15, 0], 61 | extrapolate: 'clamp', 62 | }); 63 | translateY = this.coverScale.interpolate({ 64 | inputRange: [0, 0.5, 1], 65 | outputRange: [150, 50, -155], 66 | extrapolate: 'clamp', 67 | }); 68 | scale = this.coverScale.interpolate({ 69 | inputRange: [0, 0.5, 1], 70 | outputRange: [1, 1.12, 1.25], 71 | extrapolate: 'clamp', 72 | }); 73 | render() { 74 | return ( 75 | item.name} 88 | scrollEventThrottle={1} 89 | renderItem={({ item, index }) => ( 90 | 99 | this.animate()} 102 | style={styles.touchableHeight} 103 | > 104 | 105 | 106 | 119 | 120 | 128 | 129 | {item.name} 130 | 131 | 132 | 144 | 145 | {item.cardTitle} 146 | 147 | {item.cardText} 148 | 149 | 150 | 151 | 152 | 153 | )} 154 | /> 155 | ); 156 | } 157 | } 158 | --------------------------------------------------------------------------------