├── .babelrc ├── .buckconfig ├── .exponent ├── packager-info.json └── settings.json ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .watchmanconfig ├── .yo-rc.json ├── README.md ├── exp.json ├── index.js ├── package.json ├── readmeAssets ├── buttons.gif ├── heart.gif ├── scroll.gif ├── svg.gif └── tvShowPage.gif ├── src ├── App.js ├── Scenes.js ├── appStyle.js ├── assets │ ├── back_chevron.png │ ├── logo.png │ └── tvShowsData.js ├── components │ ├── Button.js │ ├── LogoTitle.js │ ├── Page.js │ ├── TvShow │ │ ├── Image.js │ │ ├── NextEpisode.js │ │ ├── Title.js │ │ ├── TvShowListItem.js │ │ └── index.js │ └── index.js └── pages │ ├── Button.js │ ├── Heart.js │ ├── Home.js │ ├── PageTransition.js │ ├── ScrollAnimatedTvShow.js │ ├── ScrollAnimation.js │ ├── Svg.js │ └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "babel-preset-exponent" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.exponent/packager-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "exponentServerPort": 19001, 3 | "packagerPort": 19002, 4 | "packagerPid": 58232, 5 | "exponentServerNgrokUrl": "https://8t-4r2.nhacsam.animationdemo.exp.direct", 6 | "packagerNgrokUrl": "https://packager.8t-4r2.nhacsam.animationdemo.exp.direct", 7 | "ngrokPid": 58271 8 | } -------------------------------------------------------------------------------- /.exponent/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "hostType": "tunnel", 3 | "lanType": "ip", 4 | "dev": true, 5 | "strict": false, 6 | "minify": false, 7 | "urlType": "exp", 8 | "urlRandomness": "8t-4r2" 9 | } -------------------------------------------------------------------------------- /.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 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | module.system=haste 26 | 27 | experimental.strict_type_args=true 28 | 29 | munge_underscores=true 30 | 31 | 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' 32 | 33 | suppress_type=$FlowIssue 34 | suppress_type=$FlowFixMe 35 | suppress_type=$FixMe 36 | 37 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-6]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 38 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-6]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 40 | 41 | unsafe.enable_getters_and_setters=true 42 | 43 | [version] 44 | ^0.36.0 45 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | android/app/libs 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-rn-toolbox": { 3 | "base": true 4 | } 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Animation Demo 2 | -------------- 3 | 4 | Some animation demo on react-native 5 | 6 | Downloadable on exponent : exp.host/@nhacsam/react-native-animation-demo 7 | 8 | 9 | ### Buttons 10 | 11 | [Component](https://github.com/bamlab/animation-demo/blob/master/src/components/Button.js) 12 | 13 | ![Buttons animation](./readmeAssets/buttons.gif) 14 | 15 | ### Page Animation 16 | 17 | [Component](https://github.com/bamlab/animation-demo/blob/master/src/components/TvShow/TvShowListItem.js) 18 | 19 | ![Page animation](./readmeAssets/tvShowPage.gif) 20 | 21 | ### Bouncing Heart 22 | 23 | [Component](https://github.com/bamlab/animation-demo/blob/master/src/pages/Heart.js) 24 | 25 | ![Page animation](./readmeAssets/heart.gif) 26 | 27 | ### Scroll Animation 28 | 29 | [Component](https://github.com/bamlab/animation-demo/blob/master/src/pages/ScrollAnimatedTvShow.js) 30 | [Library react-native-image-header-scroll-view](https://github.com/bamlab/react-native-image-header-scroll-view) 31 | 32 | ![Scroll animation](./readmeAssets/scroll.gif) 33 | 34 | ### SVG animation 35 | 36 | [Component](https://github.com/bamlab/animation-demo/blob/master/src/pages/Svg.js) 37 | 38 | ![Svg animation](./readmeAssets/svg.gif) 39 | 40 | 41 | -------------------------------------------------------------------------------- /exp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-animation-demo", 3 | "description": "React native animation demo", 4 | "slug": "react-native-animation-demo", 5 | "sdkVersion": "14.0.0", 6 | "version": "1.0.0", 7 | "orientation": "portrait", 8 | "primaryColor": "#cccccc", 9 | "iconUrl": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png", 10 | "notification": { 11 | "iconUrl": "https://s3.amazonaws.com/exp-us-standard/placeholder-push-icon-blue-circle.png", 12 | "color": "#000000" 13 | }, 14 | "loading": { 15 | "iconUrl": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png", 16 | "hideExponentText": false 17 | }, 18 | "packagerOpts": { 19 | "assetExts": [ 20 | "ttf" 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import Exponent from 'exponent'; 2 | import App from 'animationDemo/src/App'; 3 | 4 | Exponent.registerRootComponent(App) 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "animationDemo", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "@exponent/vector-icons": "~2.0.3", 11 | "exponent": "~14.0.0", 12 | "react": "~15.4.0", 13 | "react-native": "https://github.com/exponent/react-native/archive/sdk-14.0.0.tar.gz", 14 | "react-native-animatable": "^1.1.0", 15 | "react-native-image-header-scroll-view": "^0.4.0", 16 | "react-native-vector-icons": "^4.0.0", 17 | "react-navigation": "^1.0.0-beta.6" 18 | }, 19 | "devDependencies": { 20 | "babel-jest": "18.0.0", 21 | "babel-preset-react-native": "1.9.1", 22 | "jest": "18.1.0", 23 | "react-test-renderer": "15.4.2" 24 | }, 25 | "jest": { 26 | "preset": "react-native" 27 | }, 28 | "main": "" 29 | } 30 | -------------------------------------------------------------------------------- /readmeAssets/buttons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/readmeAssets/buttons.gif -------------------------------------------------------------------------------- /readmeAssets/heart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/readmeAssets/heart.gif -------------------------------------------------------------------------------- /readmeAssets/scroll.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/readmeAssets/scroll.gif -------------------------------------------------------------------------------- /readmeAssets/svg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/readmeAssets/svg.gif -------------------------------------------------------------------------------- /readmeAssets/tvShowPage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/readmeAssets/tvShowPage.gif -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Scenes from './Scenes'; 3 | import { UIManager } from 'react-native'; 4 | 5 | UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true); 6 | 7 | const App = () => (); 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /src/Scenes.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { BackAndroid } from 'react-native'; 3 | import { StackNavigator, addNavigationHelpers } from 'react-navigation'; 4 | import appStyle from './appStyle'; 5 | 6 | import * as Pages from './pages'; 7 | 8 | export const Navigator = StackNavigator( 9 | { 10 | home: { 11 | screen: Pages.Home, 12 | }, 13 | button: { 14 | screen: Pages.Button, 15 | }, 16 | pageTransition: { 17 | screen: Pages.PageTransition, 18 | }, 19 | heart: { 20 | screen: Pages.Heart, 21 | }, 22 | scrollAnimation: { 23 | screen: Pages.ScrollAnimation, 24 | }, 25 | scrollAnimatedTvShow: { 26 | screen: Pages.ScrollAnimatedTvShow, 27 | }, 28 | svg: { 29 | screen: Pages.Svg, 30 | }, 31 | }, 32 | { 33 | initialRouteName: 'home', 34 | headerMode: 'screen', 35 | navigationOptions: { 36 | header: { 37 | tintColor: appStyle.colors.lightText, 38 | style: { 39 | backgroundColor: appStyle.colors.primary, 40 | borderBottomWidth: 0, 41 | }, 42 | }, 43 | }, 44 | }, 45 | ); 46 | 47 | export default Navigator; 48 | -------------------------------------------------------------------------------- /src/appStyle.js: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native'; 2 | 3 | const navbarOffset = Platform.OS === 'ios' ? 20 : 0; 4 | const navbarBaseHeight = Platform.OS === 'ios' ? 44 : 30; 5 | 6 | export const appStyle = { 7 | navbar: { 8 | offset: navbarOffset, 9 | baseHeight: navbarBaseHeight, 10 | height: navbarBaseHeight + navbarOffset, 11 | }, 12 | font: { 13 | fontSize: { 14 | small: 11, 15 | default: 13, 16 | big: 15, 17 | large: 17, 18 | huge: 20, 19 | }, 20 | }, 21 | colors: { 22 | primary: '#05A5D1', 23 | lightText: '#FAFAFA', 24 | background: '#F5FCFF', 25 | }, 26 | margins: { 27 | inner: 10, 28 | outer: 25, 29 | }, 30 | dimensions: { 31 | touchableHeight: 48, 32 | visibleButtonHeight: 36, 33 | largeButtonHeight: 50, 34 | largeButtonWidth: 250, 35 | }, 36 | }; 37 | 38 | export default appStyle; 39 | -------------------------------------------------------------------------------- /src/assets/back_chevron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/src/assets/back_chevron.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bamlab/animation-demo/48c5e522e722f8f5f8c9e24c1a6252583ad591bc/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/tvShowsData.js: -------------------------------------------------------------------------------- 1 | export default {"page":1,"results":[{"poster_path":"\/mBDlsOhNOV1MkNii81aT14EYQ4S.jpg","popularity":58.245824,"id":44217,"backdrop_path":"\/A30ZqEoDbchvE7mCZcSp6TEwB1Q.jpg","vote_average":6.96,"overview":"Vikings follows the adventures of Ragnar Lothbrok, the greatest hero of his age. The series tells the sagas of Ragnar's band of Viking brothers and his family, as he rises to become King of the Viking tribes. As well as being a fearless warrior, Ragnar embodies the Norse traditions of devotion to the gods. Legend has it that he was a direct descendant of Odin, the god of war and warriors.","first_air_date":"2013-03-03","origin_country":["IE","CA"],"genre_ids":[18,10759],"original_language":"en","vote_count":436,"name":"Vikings","original_name":"Vikings"},{"poster_path":"\/igDhbYQTvact1SbNDbzoeiFBGda.jpg","popularity":40.399612,"id":57243,"backdrop_path":"\/cVWsigSx97cTw1QfYFFsCMcR4bp.jpg","vote_average":6.93,"overview":"The Doctor looks and seems human. He's handsome, witty, and could be mistaken for just another man in the street. But he is a Time Lord: a 900 year old alien with 2 hearts, part of a gifted civilization who mastered time travel. The Doctor saves planets for a living – more of a hobby actually, and he's very, very good at it. He's saved us from alien menaces and evil from before time began – but just who is he?","first_air_date":"2005-03-26","origin_country":["GB"],"genre_ids":[10759,18,10765],"original_language":"en","vote_count":346,"name":"Doctor Who","original_name":"Doctor Who"},{"poster_path":"\/3iFm6Kz7iYoFaEcj4fLyZHAmTQA.jpg","popularity":36.155154,"id":1622,"backdrop_path":"\/o9OKe3M06QMLOzTl3l6GStYtnE9.jpg","vote_average":6.65,"overview":"When they were boys, Sam and Dean Winchester lost their mother to a mysterious and demonic supernatural force. Subsequently, their father raised them to be soldiers. He taught them about the paranormal evil that lives in the dark corners and on the back roads of America ... and he taught them how to kill it. Now, the Winchester brothers crisscross the country in their '67 Chevy Impala, battling every kind of supernatural threat they encounter along the way. ","first_air_date":"2005-09-13","origin_country":["US"],"genre_ids":[18,9648,10765],"original_language":"en","vote_count":453,"name":"Supernatural","original_name":"Supernatural"},{"poster_path":"\/wQoosZYg9FqPrmI4zeCLRdEbqAB.jpg","popularity":33.992454,"id":1418,"backdrop_path":"\/nGsNruW3W27V6r4gkyc3iiEGsKR.jpg","vote_average":6.93,"overview":"The Big Bang Theory is centered on five characters living in Pasadena, California: roommates Leonard Hofstadter and Sheldon Cooper; Penny, a waitress and aspiring actress who lives across the hall; and Leonard and Sheldon's equally geeky and socially awkward friends and co-workers, mechanical engineer Howard Wolowitz and astrophysicist Raj Koothrappali. The geekiness and intellect of the four guys is contrasted for comic effect with Penny's social skills and common sense.","first_air_date":"2007-09-24","origin_country":["US"],"genre_ids":[35],"original_language":"en","vote_count":927,"name":"The Big Bang Theory","original_name":"The Big Bang Theory"},{"poster_path":"\/f9zGxLHGyQB10cMDZNY5ZcGKhZi.jpg","popularity":32.225203,"id":19885,"backdrop_path":"\/bvS50jBZXtglmLu72EAt5KgJBrL.jpg","vote_average":7.86,"overview":"A modern update finds the famous sleuth and his doctor partner solving crime in 21st century London.","first_air_date":"2010-07-25","origin_country":["GB"],"genre_ids":[80,18,9648],"original_language":"en","vote_count":400,"name":"Sherlock","original_name":"Sherlock"},{"poster_path":"\/jIhL6mlT7AblhbHJgEoiBIOUVl1.jpg","popularity":31.92283,"id":1399,"backdrop_path":"\/mUkuc2wyV9dHLG0D0Loaw5pO2s8.jpg","vote_average":7.87,"overview":"Seven noble families fight for control of the mythical land of Westeros. Friction between the houses leads to full-scale war. All while a very ancient evil awakens in the farthest north. Amidst the war, a neglected military order of misfits, the Night's Watch, is all that stands between the realms of men and icy horrors beyond.","first_air_date":"2011-04-17","origin_country":["US"],"genre_ids":[10759,18,10765],"original_language":"en","vote_count":1514,"name":"Game of Thrones","original_name":"Game of Thrones"},{"poster_path":"\/jZn7dEHRRjXcT43D9GMHxzASDef.jpg","popularity":29.486047,"id":18165,"backdrop_path":"\/3O4r2guye3WwLBNPTfpfecU1FBn.jpg","vote_average":6.49,"overview":"The story of two vampire brothers obsessed with the same girl, who bears a striking resemblance to the beautiful but ruthless vampire they knew and loved in 1864.","first_air_date":"2009-09-10","origin_country":["US"],"genre_ids":[18,14,27,10749,53],"original_language":"en","vote_count":197,"name":"The Vampire Diaries","original_name":"The Vampire Diaries"},{"poster_path":"\/vxuoMW6YBt6UsxvMfRNwRl9LtWS.jpg","popularity":28.604387,"id":1402,"backdrop_path":"\/zYFQM9G5j9cRsMNMuZAX64nmUMf.jpg","vote_average":7.39,"overview":"Sheriff's deputy Rick Grimes awakens from a coma to find a post-apocalyptic world dominated by flesh-eating zombies. He sets out to find his family and encounters many other survivors along the way.","first_air_date":"2010-10-31","origin_country":["US"],"genre_ids":[10759,18],"original_language":"en","vote_count":1057,"name":"The Walking Dead","original_name":"The Walking Dead"},{"poster_path":"\/yTZQkSsxUFJZJe67IenRM0AEklc.jpg","popularity":26.768635,"id":456,"backdrop_path":"\/f5uNbUC76oowt5mt5J9QlqrIYQ6.jpg","vote_average":6.89,"overview":"Set in Springfield, the average American town, the show focuses on the antics and everyday adventures of the Simpson family; Homer, Marge, Bart, Lisa and Maggie, as well as a virtual cast of thousands. Since the beginning, the series has been a pop culture icon, attracting hundreds of celebrities to guest star. The show has also made name for itself in its fearless satirical take on politics, media and American life in general.","first_air_date":"1989-12-16","origin_country":["US"],"genre_ids":[16,35,10751],"original_language":"en","vote_count":448,"name":"The Simpsons","original_name":"The Simpsons"},{"poster_path":"\/hNEC8dcLXeQllaP8JfCHJSPOMhk.jpg","popularity":25.705154,"id":65708,"backdrop_path":"\/9qyqo9KsvYHkWREAKU9KoCG53IL.jpg","vote_average":7.16,"overview":"Adventurer James Keziah Delaney returns to London from Africa in 1814 along with fourteen stolen diamonds to seek vengeance after the death of his father.","first_air_date":"2017-01-07","origin_country":["GB","US"],"genre_ids":[18],"original_language":"en","vote_count":34,"name":"Taboo","original_name":"Taboo"},{"poster_path":"\/lUFK7ElGCk9kVEryDJHICeNdmd1.jpg","popularity":23.775322,"id":60735,"backdrop_path":"\/mmxxEpTqVdwBlu5Pii7tbedBkPC.jpg","vote_average":6.67,"overview":"After a particle accelerator causes a freak storm, CSI Investigator Barry Allen is struck by lightning and falls into a coma. Months later he awakens with the power of super speed, granting him the ability to move through Central City like an unseen guardian angel. Though initially excited by his newfound powers, Barry is shocked to discover he is not the only \"meta-human\" who was created in the wake of the accelerator explosion -- and not everyone is using their new powers for good. Barry partners with S.T.A.R. Labs and dedicates his life to protect the innocent. For now, only a few close friends and associates know that Barry is literally the fastest man alive, but it won't be long before the world learns what Barry Allen has become...The Flash.","first_air_date":"2014-10-07","origin_country":["US"],"genre_ids":[18,10765],"original_language":"en","vote_count":618,"name":"The Flash","original_name":"The Flash"},{"poster_path":"\/aI4bobthe7OORg4s2zjm0f0FdC1.jpg","popularity":23.598434,"id":1416,"backdrop_path":"\/rIu4XdgSV50B6nhgUuEPuufHsB2.jpg","vote_average":5.6,"overview":"Follows the personal and professional lives of a group of doctors at Seattle’s Grey Sloan Memorial Hospital.","first_air_date":"2005-03-27","origin_country":["US"],"genre_ids":[18],"original_language":"en","vote_count":202,"name":"Grey's Anatomy","original_name":"Grey's Anatomy"},{"poster_path":"\/v2YfSiVQYMVRJa6yxs4DoDHmPv6.jpg","popularity":21.719883,"id":4614,"backdrop_path":"\/nymeWHYQ1JaWP2wyNW5a5WHiDCd.jpg","vote_average":6.22,"overview":"NCIS is an American police procedural drama television series, revolving around a fictional team of special agents from the Naval Criminal Investigative Service, which conducts criminal investigations involving the U.S. Navy and Marine Corps.","first_air_date":"2003-09-23","origin_country":["US"],"genre_ids":[28,12,80,18],"original_language":"en","vote_count":210,"name":"NCIS","original_name":"NCIS"},{"poster_path":"\/gBGUL1UTUNmdRQT8gA1LUV4yg39.jpg","popularity":21.642873,"id":1434,"backdrop_path":"\/pH38r4TWTqq7Mcs6XAlwgzNUeJe.jpg","vote_average":6.42,"overview":"Sick, twisted, politically incorrect and Freakin' Sweet animated series featuring the adventures of the dysfunctional Griffin family. Bumbling Peter and long-suffering Lois have three kids. Stewie (a brilliant but sadistic baby bent on killing his mother and taking over the world), Meg (the oldest, and is the most unpopular girl in town) and Chris (the middle kid, he's not very bright but has a passion for movies). The final member of the family is Brian - a talking dog and much more than a pet, he keeps Stewie in check whilst sipping Martinis and sorting through his own life issues.","first_air_date":"1999-01-31","origin_country":["US"],"genre_ids":[16,35],"original_language":"en","vote_count":314,"name":"Family Guy","original_name":"Family Guy"},{"poster_path":"\/efrDcB26bugOroNshsPSrPEwJAI.jpg","popularity":21.316139,"id":39351,"backdrop_path":"\/ocWDGFHxddYWcZYeenO1y7ULeIi.jpg","vote_average":6.22,"overview":"After Portland homicide detective Nick Burkhardt discovers he's descended from an elite line of criminal profilers known as \"Grimms,\" he increasingly finds his responsibilities as a detective at odds with his new responsibilities as a Grimm.","first_air_date":"2011-10-28","origin_country":["US"],"genre_ids":[18,14,9648],"original_language":"en","vote_count":159,"name":"Grimm","original_name":"Grimm"},{"poster_path":"\/mWnHXN6uWFAnySGxN9TljNKnwj6.jpg","popularity":20.213638,"id":4629,"backdrop_path":"\/qOc3Y92gNfhIXSH59GCIKqkVhSK.jpg","vote_average":7.81,"overview":"The story of Stargate SG-1 begins about a year after the events of the feature film, when the United States government learns that an ancient alien device called the Stargate can access a network of such devices on a multitude of planets. SG-1 is an elite Air Force special operations team, one of more than two dozen teams from Earth who explore the galaxy and defend against alien threats such as the Goa'uld, Replicators, and the Ori.","first_air_date":"1997-07-27","origin_country":["CA","US"],"genre_ids":[28,12,14,878],"original_language":"en","vote_count":160,"name":"Stargate SG-1","original_name":"Stargate SG-1"},{"poster_path":"\/1yeVJox3rjo2jBKrrihIMj7uoS9.jpg","popularity":20.205195,"id":1396,"backdrop_path":"\/eSzpy96DwBujGFj0xMbXBcGcfxX.jpg","vote_average":8.02,"overview":"Breaking Bad is an American crime drama television series created and produced by Vince Gilligan. Set and produced in Albuquerque, New Mexico, Breaking Bad is the story of Walter White, a struggling high school chemistry teacher who is diagnosed with inoperable lung cancer at the beginning of the series. He turns to a life of crime, producing and selling methamphetamine, in order to secure his family's financial future before he dies, teaming with his former student, Jesse Pinkman. Heavily serialized, the series is known for positioning its characters in seemingly inextricable corners and has been labeled a contemporary western by its creator.","first_air_date":"2008-01-19","origin_country":["US"],"genre_ids":[18],"original_language":"en","vote_count":921,"name":"Breaking Bad","original_name":"Breaking Bad"},{"poster_path":"\/v7K2RUuqlb9bDthKqvBKI3F0biu.jpg","popularity":19.90251,"id":34307,"backdrop_path":"\/wbPCtpinXTxdBR9DvXlKJG3FU0f.jpg","vote_average":7.46,"overview":"Chicagoan Frank Gallagher is the proud single dad of six smart, industrious, independent kids, who without him would be... perhaps better off. When Frank's not at the bar spending what little money they have, he's passed out on the floor. But the kids have found ways to grow up in spite of him. They may not be like any family you know, but they make no apologies for being exactly who they are.","first_air_date":"2011-01-09","origin_country":["US"],"genre_ids":[18,35],"original_language":"en","vote_count":199,"name":"Shameless","original_name":"Shameless"},{"poster_path":"\/17x3Koxd7mqSe2KZWR1K2qtXNsc.jpg","popularity":19.875588,"id":1403,"backdrop_path":"\/jOrfoGipT8QoDi54Qd9f5yhJCgw.jpg","vote_average":6.39,"overview":"Agent Phil Coulson of S.H.I.E.L.D. (Strategic Homeland Intervention, Enforcement and Logistics Division) puts together a team of agents to investigate the new, the strange and the unknown around the globe, protecting the ordinary from the extraordinary.","first_air_date":"2013-09-24","origin_country":["US"],"genre_ids":[14,18,28,12,878],"original_language":"en","vote_count":317,"name":"Marvel's Agents of S.H.I.E.L.D.","original_name":"Marvel's Agents of S.H.I.E.L.D."},{"poster_path":"\/mo0FP1GxOFZT4UDde7RFDz5APXF.jpg","popularity":19.706788,"id":1412,"backdrop_path":"\/dXTyVDTIgeByvUOUEiHjbi8xX9A.jpg","vote_average":6.46,"overview":"Spoiled billionaire playboy Oliver Queen is missing and presumed dead when his yacht is lost at sea. He returns five years later a changed man, determined to clean up the city as a hooded vigilante armed with a bow.","first_air_date":"2012-10-10","origin_country":["CA","US"],"genre_ids":[28,12,80,18,9648,878],"original_language":"en","vote_count":534,"name":"Arrow","original_name":"Arrow"}],"total_results":19999,"total_pages":1000} 2 | 3 | -------------------------------------------------------------------------------- /src/components/Button.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes, Component } from 'react'; 2 | import { TouchableOpacity, Text, StyleSheet, View, ActivityIndicator, LayoutAnimation } from 'react-native'; 3 | import Icon from 'react-native-vector-icons/MaterialIcons'; 4 | 5 | import appStyle from 'animationDemo/src/appStyle'; 6 | import * as Animatable from 'react-native-animatable'; // step 2 7 | 8 | const styles = StyleSheet.create({ 9 | container: { 10 | justifyContent: 'center', 11 | alignItems: 'center', 12 | minHeight: appStyle.dimensions.touchableHeight * 1.3, 13 | marginVertical: appStyle.margins.inner, 14 | minWidth: 2*appStyle.dimensions.largeButtonHeight, 15 | }, 16 | button: { 17 | alignSelf: 'stretch', 18 | justifyContent: 'center', 19 | height: appStyle.dimensions.largeButtonHeight, 20 | backgroundColor: appStyle.colors.lightText, 21 | borderRadius: 30, 22 | overflow: 'hidden', // step 1 23 | }, 24 | buttonIdle: { 25 | height: appStyle.dimensions.touchableHeight, 26 | paddingHorizontal: appStyle.margins.inner, 27 | minWidth: appStyle.dimensions.largeButtonWidth, 28 | }, 29 | buttonFetching: { 30 | alignSelf: 'center', 31 | width: appStyle.dimensions.largeButtonHeight, 32 | }, 33 | buttonError: { 34 | alignSelf: 'center', 35 | backgroundColor: '#f44336', 36 | width: appStyle.dimensions.largeButtonHeight, 37 | }, 38 | buttonSuccess: { 39 | alignSelf: 'center', 40 | backgroundColor: '#4caf50', 41 | width: appStyle.dimensions.largeButtonHeight, 42 | }, 43 | text: { 44 | textAlign: 'center', 45 | color: '#1a237e', 46 | fontSize: appStyle.font.fontSize.big, 47 | }, 48 | textWhite: { 49 | textAlign: 'center', 50 | color: appStyle.colors.lightText, 51 | backgroundColor: 'transparent', 52 | } 53 | }); 54 | 55 | class Button extends Component { 56 | 57 | status = { 58 | IDLE: 'idle', 59 | ERROR: 'error', 60 | SUCCESS: 'success', 61 | FETCHING: 'fetching', 62 | }; 63 | 64 | constructor() { 65 | super(); 66 | this.state = { 67 | status: this.status.IDLE, 68 | }; 69 | } 70 | 71 | componentWillReceiveProps(nextProps) { 72 | let nextStatus = this.status.IDLE; 73 | if (nextProps.isFetching) { 74 | nextStatus = this.status.FETCHING; 75 | } 76 | if (nextProps.isError) { 77 | nextStatus = this.status.ERROR; 78 | } 79 | if (nextProps.isSuccess) { 80 | nextStatus = this.status.SUCCESS; 81 | } 82 | 83 | if (nextStatus === this.state.status) { 84 | return; 85 | } 86 | this.setState({status: nextStatus}); 87 | 88 | this.restoreAfterTimer(nextStatus); 89 | this.launchAnimation(nextStatus); // step 2 90 | } 91 | 92 | restoreAfterTimer(fromStatus) { 93 | setTimeout(() => { 94 | if (fromStatus === this.status.FETCHING || this.state.status !== fromStatus) { 95 | return; 96 | } 97 | this.setState({status: this.status.IDLE}); 98 | }, 3000); 99 | } 100 | 101 | launchAnimation(status) { 102 | if (status === this.status.ERROR) { 103 | this.refs.button.rotate(300); 104 | setTimeout(() => this.refs.button.shake(400), 400); 105 | } 106 | if (status === this.status.SUCCESS) { 107 | this.refs.button.rotate(300); 108 | } 109 | } 110 | 111 | 112 | componentWillUpdate() { 113 | LayoutAnimation.easeInEaseOut(); // step 1 114 | } 115 | 116 | getContent() { 117 | switch(this.state.status) { 118 | case this.status.FETCHING: 119 | return ( 120 | 121 | ); 122 | 123 | case this.status.ERROR: 124 | return ( 125 | ! 126 | ); 127 | 128 | case this.status.SUCCESS: 129 | return ; 130 | 131 | default: 132 | return ( 133 | {this.props.children.toUpperCase()} 134 | ); 135 | } 136 | } 137 | 138 | getButtonStyle() { 139 | switch(this.state.status) { 140 | case this.status.FETCHING: 141 | return styles.buttonFetching 142 | case this.status.ERROR: 143 | return styles.buttonError; 144 | case this.status.SUCCESS: 145 | return styles.buttonSuccess 146 | default: 147 | return styles.buttonIdle; 148 | } 149 | } 150 | 151 | render() { 152 | const props = this.props; 153 | const buttonStyle = this.getButtonStyle(); 154 | 155 | // step 2 : Animatable.View 156 | return ( 157 | 158 | 159 | { this.getContent()} 160 | 161 | 162 | ); 163 | } 164 | } 165 | 166 | Button.propTypes = { 167 | children: PropTypes.string, 168 | onPress: PropTypes.func, 169 | buttonType: PropTypes.string, 170 | isFetching: PropTypes.bool, 171 | isError: PropTypes.bool, 172 | isSuccess: PropTypes.bool, 173 | style: View.propTypes.style, 174 | }; 175 | 176 | export default Button; 177 | -------------------------------------------------------------------------------- /src/components/LogoTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, Image, StyleSheet } from 'react-native'; 3 | 4 | import logo from 'animationDemo/src/assets/logo.png'; 5 | import appStyle from 'animationDemo/src/appStyle'; 6 | 7 | const styles = StyleSheet.create({ 8 | container: { 9 | flex: 1, 10 | justifyContent: 'center', 11 | alignItems: 'center', 12 | marginTop: appStyle.navbar.offset, 13 | }, 14 | image: { 15 | height: appStyle.navbar.baseHeight - 8, 16 | resizeMode: 'contain', 17 | }, 18 | }); 19 | 20 | const LogoTitle = () => ( 21 | 22 | 23 | 24 | ); 25 | 26 | export default LogoTitle; 27 | -------------------------------------------------------------------------------- /src/components/Page.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { View, StyleSheet } from 'react-native'; 3 | import appStyle from 'animationDemo/src/appStyle'; 4 | 5 | const styles = StyleSheet.create({ 6 | page: { 7 | flex: 1, 8 | flexDirection: 'column', 9 | justifyContent: 'flex-start', 10 | }, 11 | }); 12 | 13 | const Page = props => ( 14 | 20 | {props.children} 21 | 22 | ); 23 | 24 | Page.propTypes = { 25 | children: PropTypes.node, 26 | noMargin: PropTypes.bool, 27 | noNavBar: PropTypes.bool, 28 | backgroundColor: PropTypes.string, 29 | }; 30 | 31 | 32 | Page.defaultProps = { 33 | noMargin: false, 34 | noNavBar: false, 35 | backgroundColor: appStyle.colors.color, 36 | }; 37 | 38 | export default Page; 39 | -------------------------------------------------------------------------------- /src/components/TvShow/Image.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { View, StyleSheet, Image } from 'react-native'; 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | flex: 1, 7 | }, 8 | image: { 9 | flex: 1, 10 | zIndex: 1, 11 | resizeMode: 'cover', 12 | }, 13 | shadow: { 14 | shadowColor: 'black', 15 | shadowOffset: {width: 2, height: 10}, 16 | shadowOpacity: .30, 17 | shadowRadius: 10, 18 | marginLeft: 15, 19 | marginRight: 5, 20 | }, 21 | }); 22 | 23 | const TvShowImage = props => ( 24 | 25 | 28 | 29 | ); 30 | 31 | TvShowImage.propTypes = { 32 | tvShow: PropTypes.object.isRequired, 33 | noShadow: PropTypes.bool, 34 | style: PropTypes.any, 35 | }; 36 | 37 | TvShowImage.defaultProps = { 38 | }; 39 | 40 | export default TvShowImage; 41 | 42 | -------------------------------------------------------------------------------- /src/components/TvShow/NextEpisode.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { View, Text, StyleSheet, Image, TouchableHighlight, TouchableWithoutFeedback } from 'react-native'; 3 | import appStyle from 'animationDemo/src/appStyle'; 4 | import * as Animatable from 'react-native-animatable'; 5 | 6 | const styles = StyleSheet.create({ 7 | touchable: { 8 | flex: 1, 9 | }, 10 | square: { 11 | flex: 1, 12 | justifyContent: 'center', 13 | padding: 30, 14 | }, 15 | text: { 16 | color: appStyle.colors.primary, 17 | fontSize: appStyle.font.fontSize.huge, 18 | maxWidth: 140, 19 | backgroundColor: 'transparent', 20 | }, 21 | }); 22 | 23 | const NextEpisode = props => ( 24 | 28 | 29 | 30 | {props.tvShow.vote_average} 31 | 32 | 33 | 34 | ); 35 | 36 | NextEpisode.propTypes = { 37 | tvShow: PropTypes.object.isRequired, 38 | style: PropTypes.any, 39 | color: PropTypes.string, 40 | }; 41 | 42 | NextEpisode.defaultProps = { 43 | color: 'white', 44 | }; 45 | 46 | export default NextEpisode; 47 | 48 | -------------------------------------------------------------------------------- /src/components/TvShow/Title.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { View, Text, StyleSheet, Image, TouchableHighlight, TouchableWithoutFeedback } from 'react-native'; 3 | import appStyle from 'animationDemo/src/appStyle'; 4 | 5 | const styles = StyleSheet.create({ 6 | touchable: { 7 | flex: 1, 8 | zIndex: 2, 9 | }, 10 | square: { 11 | flex: 1, 12 | opacity: 0.95, 13 | justifyContent: 'center', 14 | padding: 30, 15 | }, 16 | text: { 17 | color: appStyle.colors.lightText, 18 | fontSize: appStyle.font.fontSize.huge, 19 | maxWidth: 140, 20 | }, 21 | shadow: { 22 | shadowColor: 'black', 23 | shadowOffset: {width: 2, height: 5}, 24 | shadowOpacity: .14, 25 | shadowRadius: 10, 26 | }, 27 | }); 28 | 29 | const Title = props => ( 30 | 34 | 39 | 40 | {props.tvShow.name} 41 | 42 | 43 | 44 | ); 45 | 46 | Title.propTypes = { 47 | tvShow: PropTypes.object.isRequired, 48 | onPress: PropTypes.func, 49 | style: PropTypes.any, 50 | color: PropTypes.string, 51 | noShadow: PropTypes.bool, 52 | }; 53 | 54 | Title.defaultProps = { 55 | color: '#7e57c2', 56 | }; 57 | 58 | export default Title; 59 | 60 | -------------------------------------------------------------------------------- /src/components/TvShow/TvShowListItem.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes, Component } from 'react'; 2 | import { 3 | View, 4 | Text, 5 | StyleSheet, 6 | Image, 7 | TouchableHighlight, 8 | TouchableWithoutFeedback, 9 | LayoutAnimation, 10 | Dimensions 11 | } from 'react-native'; 12 | import appStyle from 'animationDemo/src/appStyle'; 13 | import * as Animatable from 'react-native-animatable'; 14 | 15 | import Title from './Title'; 16 | import TvShowImage from './Image'; 17 | import NextEpisode from './NextEpisode'; 18 | 19 | const height = Dimensions.get('window').height - appStyle.navbar.height; 20 | 21 | const selectOpened = (opened, style) => opened ? style.opened : style.closed; 22 | 23 | const getStyles = (opened, left) => StyleSheet.create({ 24 | container: selectOpened(opened, { 25 | opened: { 26 | height, 27 | width: Dimensions.get('window').width, 28 | position: 'relative', 29 | zIndex: 1, 30 | marginHorizontal: 0, 31 | }, 32 | closed: { 33 | flex: 1, 34 | alignItems: 'stretch', 35 | height: 250, 36 | justifyContent: 'center', 37 | marginHorizontal: 25, 38 | }, 39 | }), 40 | title: selectOpened(opened, { 41 | opened: { 42 | height: Dimensions.get('window').width / 2, 43 | flexDirection: 'row', 44 | }, 45 | closed: { 46 | position: 'absolute', 47 | top: 25, 48 | 49 | zIndex: 2, 50 | height: 200, 51 | width: 200, 52 | left: left ? 5 : undefined, 53 | right: left ? undefined : 5 54 | } 55 | }), 56 | image: selectOpened(opened, { 57 | opened: { 58 | flex: 1 59 | }, 60 | closed: { 61 | flex: 0, 62 | height: 170, 63 | zIndex: 1, 64 | }, 65 | }), 66 | description: selectOpened(opened, { 67 | opened: { 68 | flex: 1, 69 | justifyContent: 'center', 70 | padding: 20, 71 | opacity: 0, 72 | }, 73 | closed: { 74 | position: 'absolute', 75 | opacity: 0, 76 | }, 77 | }), 78 | descriptionText: { 79 | color: appStyle.colors.lightText, 80 | textAlign: 'center', 81 | maxHeight: height / 3, 82 | }, 83 | animatableNextEpisode: selectOpened(opened, { 84 | opened: { 85 | flex: 1, 86 | zIndex: 1, 87 | }, 88 | closed: { 89 | position: 'absolute', 90 | opacity: 0, 91 | right: 0, 92 | bottom: 0, 93 | top: 0 94 | } 95 | }), 96 | }); 97 | 98 | const colors = [ 99 | '#7e57c2', 100 | '#03a9f4', 101 | '#f44336', 102 | '#009688', 103 | '#e91e63', 104 | '#4caf50', 105 | '#ff9800', 106 | '#795548', 107 | '#607d8b', 108 | '#9c27b0', 109 | '#00bcd4', 110 | '#ffc107', 111 | ]; 112 | 113 | class TvShowListItem extends Component { 114 | 115 | constructor(props) { 116 | super(props); 117 | this.state = { opened: false }; 118 | 119 | this.onPress = this.onPress.bind(this); 120 | } 121 | 122 | componentWillUpdate() { 123 | const animation = LayoutAnimation.create(500, 'easeInEaseOut', 'opacity'); 124 | LayoutAnimation.configureNext(animation); 125 | } 126 | 127 | onPress() { 128 | this.props.onPress(); 129 | if (this.props.noAnimation) { 130 | return; 131 | } 132 | 133 | if (this.state.opened) { 134 | this.refs.nextEpisode.fadeOutLeft(); 135 | this.refs.description.fadeOutDownBig(); 136 | return this.setState({opened: false, windowPos: null}); 137 | } 138 | this.refs.container.measureInWindow((x, y) => { 139 | this.refs.nextEpisode.slideInLeft(); 140 | setTimeout(() => this.refs.description.fadeInUpBig(), 400); 141 | this.setState({ 142 | opened: true, 143 | windowPos: { x, y }, 144 | }); 145 | }); 146 | } 147 | 148 | 149 | render() { 150 | const props = this.props; 151 | const { opened } = this.state; 152 | const styles = getStyles(opened, (props.index % 2 === 0)); 153 | 154 | const containerPos = this.state.windowPos ? { 155 | top: - this.state.windowPos.y + appStyle.navbar.height, 156 | } : {}; 157 | 158 | return ( 159 | 160 | 161 | 162 | 163 | 169 | <Animatable.View 170 | style={styles.animatableNextEpisode} 171 | duration={800} 172 | ref="nextEpisode" 173 | > 174 | <NextEpisode tvShow={this.props.tvShow}/> 175 | </Animatable.View> 176 | </View> 177 | <Animatable.View 178 | style={styles.description} 179 | duration={800} 180 | ref="description" 181 | delay={400} 182 | > 183 | <Text style={styles.descriptionText}>{this.props.tvShow.overview}</Text> 184 | </Animatable.View> 185 | </View> 186 | </TouchableWithoutFeedback> 187 | ); 188 | } 189 | } 190 | 191 | TvShowListItem.propTypes = { 192 | tvShow: PropTypes.object.isRequired, 193 | index: PropTypes.oneOfType([ 194 | PropTypes.number, 195 | PropTypes.string, 196 | ]), 197 | onPress: PropTypes.func, 198 | opened: PropTypes.bool, 199 | noAnimation: PropTypes.bool, 200 | }; 201 | 202 | TvShowListItem.defaultProps = { 203 | index: 0, 204 | onPress: () => {} 205 | }; 206 | 207 | export default TvShowListItem; 208 | 209 | -------------------------------------------------------------------------------- /src/components/TvShow/index.js: -------------------------------------------------------------------------------- 1 | export { default as TvShowListItem } from './TvShowListItem'; 2 | 3 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as LogoTitle } from './LogoTitle'; 2 | export { default as Page } from './Page'; 3 | export { default as Button } from './Button'; 4 | export { TvShowListItem } from './TvShow'; 5 | -------------------------------------------------------------------------------- /src/pages/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | 4 | import { Page, Button } from 'animationDemo/src/components'; 5 | 6 | 7 | const styles = StyleSheet.create({ 8 | container: { 9 | flex: 1, 10 | justifyContent: 'center', 11 | alignItems: 'center', 12 | }, 13 | }); 14 | 15 | class ButtonPage extends React.Component { 16 | 17 | static navigationOptions = { 18 | title: 'Button', 19 | }; 20 | 21 | constructor(props) { 22 | super(props); 23 | this.state = { 24 | successButton: { 25 | isFetching: false, 26 | isSuccess: false, 27 | }, 28 | errorButton: { 29 | isFetching: false, 30 | isError: false, 31 | } 32 | }; 33 | } 34 | 35 | pressSuccess() { 36 | this.setState({ 37 | successButton: { 38 | isFetching: true, 39 | isSuccess: false, 40 | }, 41 | errorButton: { 42 | isFetching: false, 43 | isError: false, 44 | } 45 | }); 46 | setTimeout(() => { 47 | this.setState({ 48 | successButton: { 49 | isFetching: false, 50 | isSuccess: true, 51 | }, 52 | }); 53 | }, 500); 54 | } 55 | 56 | pressError() { 57 | this.setState({ 58 | errorButton: { 59 | isFetching: true, 60 | isError: false, 61 | }, 62 | successButton: { 63 | isFetching: false, 64 | isSuccess: false, 65 | }, 66 | }); 67 | setTimeout(() => { 68 | this.setState({ 69 | errorButton: { 70 | isFetching: false, 71 | isError: true, 72 | }, 73 | }); 74 | }, 500); 75 | } 76 | 77 | render() { 78 | return ( 79 | <Page backgroundColor="#37474f"> 80 | <View style={styles.container}> 81 | <Button onPress={() => this.pressSuccess()} {...this.state.successButton}>Button</Button> 82 | <Button onPress={() => this.pressError()} {...this.state.errorButton}>Button</Button> 83 | </View> 84 | </Page> 85 | ); 86 | } 87 | } 88 | 89 | export default ButtonPage; 90 | -------------------------------------------------------------------------------- /src/pages/Heart.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { View, Animated, TouchableWithoutFeedback, StyleSheet } from 'react-native'; 3 | import { Button } from 'animationDemo/src/components'; 4 | 5 | import Icon from 'react-native-vector-icons/FontAwesome'; 6 | 7 | import { Page } from 'animationDemo/src/components'; 8 | 9 | const AnimatedIcon = Animated.createAnimatedComponent(Icon); 10 | 11 | class Heart extends React.Component { 12 | 13 | static navigationOptions = { 14 | title: 'Heart', 15 | }; 16 | 17 | constructor() { 18 | super(); 19 | this.state = { 20 | value: new Animated.Value(0), 21 | full: false, 22 | }; 23 | } 24 | 25 | 26 | toggle() { 27 | this.state.value.setValue(0); 28 | Animated.timing(this.state.value, { 29 | toValue: 1, 30 | duration: 500, 31 | }).start(); 32 | 33 | this.setState({ full: !this.state.full }); 34 | } 35 | 36 | render() { 37 | return ( 38 | <Page> 39 | <View style={styles.container}> 40 | <TouchableWithoutFeedback 41 | underlayColor="transparent" 42 | onPress={() => this.toggle()} 43 | > 44 | <AnimatedIcon 45 | name={this.state.full ? 'heart' : 'heart-o'} 46 | style={{ 47 | fontSize: 40, 48 | color: this.state.full ? '#dddd00' : 'black', 49 | transform: [ 50 | { 51 | scale: this.state.value.interpolate({ 52 | inputRange: [0, 0.6, 1], 53 | outputRange: [1, 1.5, 1], 54 | }), 55 | }, 56 | ], 57 | }} 58 | /> 59 | </TouchableWithoutFeedback> 60 | </View> 61 | </Page> 62 | ); 63 | } 64 | } 65 | 66 | const styles = StyleSheet.create({ 67 | container: { 68 | flex: 1, 69 | justifyContent: 'center', 70 | alignItems: 'center', 71 | }, 72 | }); 73 | 74 | export default Heart; 75 | -------------------------------------------------------------------------------- /src/pages/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text, View } from 'react-native'; 3 | 4 | import appStyle from 'animationDemo/src/appStyle'; 5 | 6 | import { Page, Button } from 'animationDemo/src/components'; 7 | 8 | const styles = StyleSheet.create({ 9 | container: { 10 | flex: 1, 11 | justifyContent: 'center', 12 | alignItems: 'center', 13 | }, 14 | button: { 15 | backgroundColor: appStyle.colors.primary, 16 | }, 17 | }); 18 | 19 | const Home = (props) => ( 20 | <Page> 21 | <View style={styles.container}> 22 | <Button onPress={() => props.navigation.navigate('button')} style={styles.button}>Button</Button> 23 | <Button onPress={() => props.navigation.navigate('pageTransition')} style={styles.button}>Page Transition</Button> 24 | <Button onPress={() => props.navigation.navigate('heart')} style={styles.button}>Heart</Button> 25 | <Button onPress={() => props.navigation.navigate('scrollAnimation')} style={styles.button}>Scroll Animation</Button> 26 | <Button onPress={() => props.navigation.navigate('svg')} style={styles.button}>SVG</Button> 27 | </View> 28 | </Page> 29 | ); 30 | 31 | Home.navigationOptions = { 32 | title: 'Home', 33 | }; 34 | 35 | export default Home; 36 | -------------------------------------------------------------------------------- /src/pages/PageTransition.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { StyleSheet, ListView, ActivityIndicator, View } from 'react-native'; 3 | import * as Animatable from 'react-native-animatable'; 4 | 5 | import { Page, TvShowListItem } from 'animationDemo/src/components'; 6 | 7 | import data from '../assets/tvShowsData'; 8 | 9 | const styles = StyleSheet.create({ 10 | page: { 11 | backgroundColor: '#90a4ae', 12 | flex: 1, 13 | justifyContent: 'center', 14 | }, 15 | }); 16 | 17 | class PageTransition extends Component { 18 | 19 | static navigationOptions = { 20 | title: 'Page Transition', 21 | }; 22 | 23 | constructor() { 24 | super(); 25 | const ds = new ListView.DataSource({ 26 | rowHasChanged: (r1, r2) => r1.id !== r2.id} 27 | ); 28 | this.state = { 29 | dataSource: ds.cloneWithRows(data.results), 30 | active: false, 31 | currentId: null 32 | }; 33 | this.listItems = {}; 34 | } 35 | 36 | toggleActive(rowID) { 37 | 38 | if (this.state.active) { 39 | this.animate(false, this.state.currentId); 40 | return this.setState({ active: false }); 41 | } 42 | 43 | this.setState({ currentId: rowID, active: true }); 44 | this.animate(true, rowID); 45 | } 46 | 47 | animate(out, currentId) { 48 | return; 49 | for (let rowId in this.listItems) { 50 | if (rowId === currentId) { 51 | continue; 52 | } 53 | const item = this.listItems[rowId]; 54 | 55 | if (out) { 56 | item.fadeOutUp(400); 57 | } else { 58 | item.fadeInUp(400); 59 | } 60 | } 61 | 62 | } 63 | 64 | render() { 65 | const { active } = this.state; 66 | 67 | return ( 68 | <Page noMargin backgroundColor="#37474f"> 69 | <ListView 70 | ref="list" 71 | dataSource={this.state.dataSource} 72 | scrollEnabled={!active} 73 | renderRow={(tvShow, sectionID, rowID) => ( 74 | <Animatable.View ref={(ref) => {this.listItems[rowID] = ref;}} style={{ flex: 1 }} > 75 | <TvShowListItem tvShow={tvShow} index={rowID} onPress={() => this.toggleActive(rowID)} /> 76 | </Animatable.View> 77 | )} 78 | enableEmptySections 79 | /> 80 | </Page> 81 | ); 82 | } 83 | } 84 | 85 | export default PageTransition; 86 | -------------------------------------------------------------------------------- /src/pages/ScrollAnimatedTvShow.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | Image, 7 | Dimensions, 8 | StatusBar, 9 | } from 'react-native'; 10 | import * as Animatable from 'react-native-animatable'; 11 | 12 | import NextEpisode from '../components/TvShow/NextEpisode'; 13 | import { Button } from 'animationDemo/src/components'; 14 | import { CardStack } from 'react-navigation'; 15 | 16 | import HeaderImageScrollView, { TriggeringView } from 'react-native-image-header-scroll-view'; 17 | 18 | const MIN_HEIGHT = CardStack.Header.HEIGHT; 19 | const MAX_HEIGHT = 250; 20 | 21 | const styles = StyleSheet.create({ 22 | image: { 23 | height: MAX_HEIGHT, 24 | width: Dimensions.get('window').width, 25 | alignSelf: 'stretch', 26 | resizeMode: 'cover', 27 | }, 28 | title: { 29 | fontSize: 20, 30 | }, 31 | name: { 32 | fontWeight: 'bold', 33 | }, 34 | section: { 35 | paddingHorizontal: 20, 36 | paddingVertical: 30, 37 | borderBottomWidth: 1, 38 | borderBottomColor: '#cccccc', 39 | backgroundColor: 'white', 40 | }, 41 | sectionTitle: { 42 | fontSize: 18, 43 | fontWeight: 'bold', 44 | paddingVertical: 20, 45 | }, 46 | sectionContent: { 47 | fontSize: 16, 48 | textAlign: 'justify', 49 | }, 50 | keywords: { 51 | flexDirection: 'row', 52 | justifyContent: 'flex-start', 53 | alignItems: 'flex-start', 54 | flexWrap: 'wrap', 55 | }, 56 | keywordContainer: { 57 | backgroundColor: '#999999', 58 | borderRadius: 10, 59 | margin: 10, 60 | padding: 10, 61 | }, 62 | keyword: { 63 | fontSize: 16, 64 | color: 'white', 65 | }, 66 | titleContainer: { 67 | flex: 1, 68 | alignSelf: 'stretch', 69 | justifyContent: 'center', 70 | alignItems: 'center', 71 | }, 72 | imageTitle: { 73 | color: 'white', 74 | backgroundColor: 'transparent', 75 | fontSize: 24, 76 | }, 77 | navTitleView: { 78 | height: MIN_HEIGHT, 79 | justifyContent: 'center', 80 | alignItems: 'center', 81 | paddingTop: 16, 82 | opacity: 0, 83 | }, 84 | navTitle: { 85 | color: 'white', 86 | fontSize: 18, 87 | backgroundColor: 'transparent', 88 | }, 89 | }); 90 | 91 | class TvShow extends Component { 92 | constructor() { 93 | super(); 94 | this.state = { showNavTitle: false }; 95 | } 96 | 97 | static navigationOptions = { 98 | header: (navigation, defaultHeader) => ({ 99 | ...defaultHeader, 100 | style: { 101 | backgroundColor: 'transparent', 102 | position: 'absolute', 103 | top: 0, 104 | } 105 | }), 106 | }; 107 | 108 | render() { 109 | const { tvShowContent } = this.props.navigation.state.params; 110 | return ( 111 | <View style={{ flex: 1 }}> 112 | <StatusBar barStyle="light-content" /> 113 | <HeaderImageScrollView 114 | maxHeight={MAX_HEIGHT} 115 | minHeight={MIN_HEIGHT} 116 | maxOverlayOpacity={0.6} 117 | minOverlayOpacity={0.3} 118 | fadeOutForeground 119 | renderHeader={() => ( 120 | <Image source={{uri: `https://image.tmdb.org/t/p/w500/${tvShowContent.backdrop_path}`}} style={styles.image} /> 121 | )} 122 | renderFixedForeground={() => ( 123 | <Animatable.View 124 | style={styles.navTitleView} 125 | ref={(navTitleView) => { this.navTitleView = navTitleView; }} 126 | > 127 | <Text style={styles.navTitle}>{tvShowContent.name}</Text> 128 | </Animatable.View> 129 | )} 130 | renderForeground={() => ( 131 | <View style={styles.titleContainer}> 132 | <Text style={styles.imageTitle}>{tvShowContent.title}</Text> 133 | </View> 134 | )} 135 | > 136 | <TriggeringView 137 | style={styles.section} 138 | onHide={() => this.navTitleView.fadeInUp(200)} 139 | onDisplay={() => this.navTitleView.fadeOut(100)} 140 | > 141 | <Text style={styles.title}> 142 | <Text style={styles.name}>{tvShowContent.name}</Text> 143 | </Text> 144 | </TriggeringView> 145 | <View style={styles.section}> 146 | <Text style={styles.sectionTitle}>Overview</Text> 147 | <Text style={styles.sectionContent}>{tvShowContent.overview}</Text> 148 | </View> 149 | <View style={styles.section}> 150 | <NextEpisode tvShow={tvShowContent} /> 151 | </View> 152 | <View style={styles.section}> 153 | <NextEpisode tvShow={tvShowContent} /> 154 | </View> 155 | <View style={styles.section}> 156 | <NextEpisode tvShow={tvShowContent} /> 157 | </View> 158 | <View style={styles.section}> 159 | <NextEpisode tvShow={tvShowContent} /> 160 | </View> 161 | </HeaderImageScrollView> 162 | </View> 163 | ); 164 | } 165 | } 166 | 167 | export default TvShow; 168 | -------------------------------------------------------------------------------- /src/pages/ScrollAnimation.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { StyleSheet, ListView, ActivityIndicator, View } from 'react-native'; 3 | 4 | import { Page, TvShowListItem } from 'animationDemo/src/components'; 5 | 6 | import data from '../assets/tvShowsData'; 7 | 8 | class ScrollAnimation extends Component { 9 | 10 | static navigationOptions = { 11 | title: 'Scroll Animation', 12 | }; 13 | 14 | constructor() { 15 | super(); 16 | const ds = new ListView.DataSource({ 17 | rowHasChanged: (r1, r2) => r1.id !== r2.id} 18 | ); 19 | this.state = { 20 | dataSource: ds.cloneWithRows(data.results), 21 | }; 22 | } 23 | 24 | render() { 25 | return ( 26 | <Page noMargin backgroundColor="#37474f"> 27 | <ListView 28 | dataSource={this.state.dataSource} 29 | renderRow={(tvShow, sectionID, rowID) => ( 30 | <View style={{ flex: 1 }} > 31 | <TvShowListItem 32 | tvShow={tvShow} index={rowID} 33 | noAnimation 34 | onPress={() => this.props.navigation.navigate('scrollAnimatedTvShow', { tvShowContent: tvShow })} 35 | /> 36 | </View> 37 | )} 38 | enableEmptySections 39 | /> 40 | </Page> 41 | ); 42 | } 43 | } 44 | 45 | export default ScrollAnimation; 46 | -------------------------------------------------------------------------------- /src/pages/Svg.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text, View, Animated } from 'react-native'; 3 | import { Button } from 'animationDemo/src/components'; 4 | 5 | 6 | import { Components } from 'exponent'; 7 | const { Svg: { Line } } = Components; 8 | 9 | const { Svg } = Components; 10 | 11 | import { Page } from 'animationDemo/src/components'; 12 | 13 | const styles = StyleSheet.create({ 14 | container: { 15 | flex: 1, 16 | justifyContent: 'center', 17 | alignItems: 'center', 18 | }, 19 | }); 20 | 21 | const iterpolate = (value, from, to) => (from + value * (to - from)); 22 | 23 | class SvgPage extends React.Component { 24 | 25 | static navigationOptions = { 26 | title: 'SVG Animation', 27 | }; 28 | 29 | constructor() { 30 | super(); 31 | this.state = { 32 | value: new Animated.Value(0), 33 | menu: true, 34 | }; 35 | this.state.value.addListener(this.onValueChange.bind(this)); 36 | this.mounted = false; 37 | } 38 | 39 | onValueChange({ value }) { 40 | this.line1.setNativeProps({ 41 | y1: `${iterpolate(value, 24, 9)}`, 42 | y2: `${iterpolate(value, 24, 41)}`, 43 | }); 44 | this.line2.setNativeProps({ 45 | y1: `${iterpolate(value, 14, 9)}`, 46 | y2: `${iterpolate(value, 14, 41)}`, 47 | }); 48 | this.line3.setNativeProps({ 49 | y1: `${iterpolate(value, 33, 41)}`, 50 | y2: `${iterpolate(value, 33, 9)}`, 51 | }); 52 | } 53 | componentDidMount() { 54 | this.mounted = true; 55 | } 56 | 57 | toggle() { 58 | if (!this.mounted) { 59 | return; 60 | } 61 | 62 | if (this.state.menu) { 63 | Animated.timing( // Uses easing functions 64 | this.state.value, // The value to drive 65 | {toValue: 1} // Configuration 66 | ).start(); 67 | 68 | return this.setState({ menu: false }); 69 | } 70 | this.setState({ menu: true }); 71 | Animated.timing( 72 | this.state.value, 73 | {toValue: 0} 74 | ).start(); 75 | } 76 | 77 | render() { 78 | return ( 79 | <Page> 80 | <Button onPress={() => this.toggle()}>Launch</Button> 81 | <View style={styles.container}> 82 | <Svg width={50} height={50} > 83 | <Line x1="9" y1="24" x2="41" y2="24" strokeWidth="3" stroke="black" 84 | ref={ref => this.line1 = ref} /> 85 | <Line x1="9" y1="14" x2="41" y2="14" strokeWidth="3" stroke="black" 86 | ref={ref => this.line2 = ref} /> 87 | <Line x1="9" y1="33" x2="41" y2="33" strokeWidth="3" stroke="black" 88 | ref={ref => this.line3 = ref} /> 89 | </Svg> 90 | </View> 91 | </Page> 92 | ); 93 | } 94 | } 95 | 96 | export default SvgPage; 97 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | export { default as Home } from './Home'; 2 | export { default as Button } from './Button'; 3 | export { default as PageTransition } from './PageTransition'; 4 | export { default as Heart } from './Heart'; 5 | export { default as ScrollAnimation } from './ScrollAnimation'; 6 | export { default as ScrollAnimatedTvShow } from './ScrollAnimatedTvShow'; 7 | export { default as Svg } from './Svg'; 8 | --------------------------------------------------------------------------------