├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .vscode ├── launchReactNative.js ├── settings.json └── typings │ ├── react-native │ └── react-native.d.ts │ └── react │ ├── react-addons-create-fragment.d.ts │ ├── react-addons-css-transition-group.d.ts │ ├── react-addons-linked-state-mixin.d.ts │ ├── react-addons-perf.d.ts │ ├── react-addons-pure-render-mixin.d.ts │ ├── react-addons-test-utils.d.ts │ ├── react-addons-transition-group.d.ts │ ├── react-addons-update.d.ts │ ├── react-dom.d.ts │ ├── react-global.d.ts │ └── react.d.ts ├── .watchmanconfig ├── GoBack.js ├── Loading.js ├── Project01-SimpleStopWatch └── index.js ├── Project02-CustomFont ├── MFJinHei_Noncommercial-Regular.ttf ├── MFTongXin_Noncommercial-Regular.ttf ├── MFZhiHei_Noncommercial-Regular.ttf └── index.js ├── Project03-PlayLocalVideo ├── VideoPlay.js ├── emoji.mp4 ├── images │ ├── playBtn.png │ ├── playBtn@2x.png │ ├── playBtn@3x.png │ ├── uie_thumb_big.png │ ├── uie_thumb_normal@2x.png │ ├── uie_thumb_selected@2x.png │ ├── videoScreenshot01.png │ ├── videoScreenshot01@2x.png │ ├── videoScreenshot01@3x.png │ ├── videoScreenshot02.png │ ├── videoScreenshot02@2x.png │ ├── videoScreenshot02@3x.png │ ├── videoScreenshot03.png │ ├── videoScreenshot03@2x.png │ ├── videoScreenshot03@3x.png │ ├── videoScreenshot04.png │ ├── videoScreenshot04@2x.png │ ├── videoScreenshot04@3x.png │ ├── videoScreenshot05.png │ ├── videoScreenshot05@2x.png │ ├── videoScreenshot05@3x.png │ ├── videoScreenshot06.png │ ├── videoScreenshot06@2x.png │ └── videoScreenshot06@3x.png └── index.js ├── Project04-SnapChatMenu ├── images │ ├── left.png │ ├── left@2x.png │ ├── right.jpg │ └── right@2x.jpg └── index.js ├── Project05-CarouselEffect ├── images │ ├── IMG_1517.png │ ├── blue.png │ ├── bodyline.png │ ├── darkvarder.png │ ├── dudu.jpg │ ├── hello.jpg │ ├── hhhhh.jpg │ └── wave.jpg └── index.js ├── Project06-FindMyLocation ├── images │ ├── 1-Eb_0OvtcxJXHZ7-IOoBsaQ.png │ ├── Find_my_location.png │ ├── Find_my_location@2x.png │ └── Find_my_location@3x.png └── index.js ├── Project07-PullToRefresh └── index.js ├── Project08-RandomGradientColorMusic ├── Ecstasy.mp3 ├── images │ ├── music play.png │ ├── music play@2x.png │ └── music play@3x.png └── index.js ├── Project09-ImageScroller ├── ImageBaseScroller.js ├── images │ ├── Steve.png │ ├── Steve@2x.png │ └── Steve@3x.png └── index.js ├── Project10-VideoBackground ├── images │ ├── LaunchImage-800-667h@2x.png │ ├── LaunchImage-800-Portrait-736h@3x.png │ ├── ambience-1.jpg │ ├── login-secondary-logo.png │ ├── login-secondary-logo@2x.png │ └── login-secondary-logo@3x.png ├── index.js └── moments.mp4 ├── Project11-ClearTableViewCell └── index.js ├── Project12-LoginAnimation ├── Login.js ├── images │ ├── Back-icon.pdf │ ├── ambience.jpg │ ├── login-secondary-logo.png │ ├── login-secondary-logo@2x.png │ └── login-secondary-logo@3x.png └── index.js ├── Project13-AnimateTableViewCell └── index.js ├── Project14-EmojiSlotMachine ├── images │ └── Hyperspace.jpg └── index.js ├── Project15-AnimatedSplash └── index.js ├── Project16-SlideMenu ├── images │ ├── avatar_IcesZKi5_400x400.jpeg │ ├── avatar_LlCpvQc2_400x400.jpg │ ├── avatar_MiDNqbJa_400x400.jpeg │ ├── avatar_catch.jpg │ ├── avatar_photo-1449182325215-d517de72c42d.jpeg │ ├── avatar_weibo_square.png │ ├── avatar_xdBqvbba_400x400.jpg │ ├── haha_bg.jpeg │ ├── live_free.png │ ├── lonely_traveler.jpg │ ├── menu.png │ ├── menu@2x.png │ ├── menu@3x.png │ └── wallpaper.jpg └── index.js ├── Project17-TumblrMenu ├── images │ ├── 1-hjGpOnCIu4sP7H4V2sdFcA.png │ ├── 22266727550_5decf72626_o.jpg │ ├── 718835727.png │ ├── 89w7SbqD_400x400.png │ ├── Audio@2x.png │ ├── Chat@2x.png │ ├── Link@2x.png │ ├── Photo@2x.png │ ├── Quote@2x.png │ └── Text@2x.png └── index.js ├── Project18-LimitCharacters ├── images │ └── avatar.jpg └── index.js ├── README.md ├── android ├── ThreetyDaysofReactNative.iml ├── app │ ├── app.iml │ ├── build.gradle │ ├── proguard-rules.pro │ ├── react.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Entypo.ttf │ │ │ ├── EvilIcons.ttf │ │ │ ├── FontAwesome.ttf │ │ │ ├── Foundation.ttf │ │ │ ├── Ionicons.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ ├── Octicons.ttf │ │ │ └── Zocial.ttf │ │ ├── java │ │ └── com │ │ │ └── threetydaysofreactnative │ │ │ └── MainActivity.java │ │ └── res │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── checkUpdate.js ├── index.android.js ├── index.ios.js ├── ios ├── ThreetyDaysofReactNative.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── ThreetyDaysofReactNative.xcscheme ├── ThreetyDaysofReactNative │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── ThreetyDaysofReactNativeTests │ ├── Info.plist │ └── ThreetyDaysofReactNativeTests.m ├── package.json ├── screen.png ├── scripts └── version │ ├── README.md │ ├── ios.sh │ ├── post.sh │ └── pre.sh └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "react-native" ], 3 | "plugins": [ 4 | "transform-decorators-legacy" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | [ 2 | "node_modules/*" 3 | ] 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | 4 | "parser": "babel-eslint", 5 | 6 | "ecmaFeatures": { 7 | "jsx": true 8 | }, 9 | 10 | "env": { 11 | "es6": true, 12 | "jasmine": true, 13 | }, 14 | 15 | "plugins": [ 16 | "react" 17 | ], 18 | 19 | // Map from global var to bool specifying if it can be redefined 20 | "globals": { 21 | "__DEV__": true, 22 | "__dirname": false, 23 | "__fbBatchedBridgeConfig": false, 24 | "alert": false, 25 | "cancelAnimationFrame": false, 26 | "clearImmediate": true, 27 | "clearInterval": false, 28 | "clearTimeout": false, 29 | "console": false, 30 | "document": false, 31 | "escape": false, 32 | "Event": false, 33 | "EventTarget": false, 34 | "exports": false, 35 | "fetch": false, 36 | "FormData": false, 37 | "global": false, 38 | "jest": false, 39 | "Map": true, 40 | "module": false, 41 | "navigator": false, 42 | "process": false, 43 | "Promise": true, 44 | "requestAnimationFrame": true, 45 | "require": false, 46 | "Set": true, 47 | "setImmediate": true, 48 | "setInterval": false, 49 | "setTimeout": false, 50 | "window": false, 51 | "XMLHttpRequest": false, 52 | "pit": false, 53 | 54 | // Flow global types. 55 | "ReactComponent": false, 56 | "ReactClass": false, 57 | "ReactElement": false, 58 | "ReactPropsCheckType": false, 59 | "ReactPropsChainableTypeChecker": false, 60 | "ReactPropTypes": false, 61 | "SyntheticEvent": false, 62 | "$Either": false, 63 | "$All": false, 64 | "$Tuple": false, 65 | "$Supertype": false, 66 | "$Subtype": false, 67 | "$Shape": false, 68 | "$Diff": false, 69 | "$Keys": false, 70 | "$Enum": false, 71 | "$Exports": false, 72 | "$FlowIssue": false, 73 | "$FlowFixMe": false, 74 | "$FixMe": false 75 | }, 76 | 77 | "rules": { 78 | "arrow-parens": 0, 79 | "jsx-quotes": 1, 80 | // React 81 | "react/display-name": 0, 82 | "react/jsx-curly-spacing": 1, 83 | "react/jsx-max-props-per-line": 0, 84 | "react/jsx-indent-props": 0, 85 | "react/jsx-no-duplicate-props": 1, 86 | "react/jsx-no-undef": 1, 87 | "react/jsx-sort-prop-types": 0, 88 | "react/jsx-sort-props": 0, 89 | "react/jsx-uses-react": 1, 90 | "react/jsx-uses-vars": 1, 91 | "react/no-danger": 0, 92 | "react/no-set-state": 0, 93 | "react/no-did-update-set-state": 1, 94 | "react/no-unknown-property": 1, 95 | "react/require-extension": 1, 96 | "react/self-closing-comp": 1, 97 | "react/wrap-multilines": 1 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs/lib/Map.js 18 | .*/node_modules/fbjs/lib/Promise.js 19 | .*/node_modules/fbjs/lib/fetch.js 20 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js 21 | .*/node_modules/fbjs/lib/isEmpty.js 22 | .*/node_modules/fbjs/lib/crc32.js 23 | .*/node_modules/fbjs/lib/ErrorUtils.js 24 | 25 | # Flow has a built-in definition for the 'react' module which we prefer to use 26 | # over the currently-untyped source 27 | .*/node_modules/react/react.js 28 | .*/node_modules/react/lib/React.js 29 | .*/node_modules/react/lib/ReactDOM.js 30 | 31 | # Ignore commoner tests 32 | .*/node_modules/commoner/test/.* 33 | 34 | # See https://github.com/facebook/flow/issues/442 35 | .*/react-tools/node_modules/commoner/lib/reader.js 36 | 37 | # Ignore jest 38 | .*/node_modules/jest-cli/.* 39 | 40 | # Ignore Website 41 | .*/website/.* 42 | 43 | [include] 44 | 45 | [libs] 46 | node_modules/react-native/Libraries/react-native/react-native-interface.js 47 | 48 | [options] 49 | module.system=haste 50 | 51 | munge_underscores=true 52 | 53 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 54 | 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\)$' -> 'RelativeImageStub' 55 | 56 | suppress_type=$FlowIssue 57 | suppress_type=$FlowFixMe 58 | suppress_type=$FixMe 59 | 60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 61 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 62 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 63 | 64 | [version] 65 | 0.21.0 66 | -------------------------------------------------------------------------------- /.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/IJ 26 | # 27 | .idea 28 | .gradle 29 | local.properties 30 | 31 | # node.js 32 | # 33 | node_modules/ 34 | npm-debug.log 35 | -------------------------------------------------------------------------------- /.vscode/launchReactNative.js: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by vscode-react-native@0.1.0 2 | // Please do not modify it manually. All changes will be lost. 3 | try { 4 | var path = require("path"); 5 | var Launcher = require("/Users/koalahuang/.vscode/extensions/vsmobile.vscode-react-native-0.1.0/out/debugger/launcher.js").Launcher; 6 | new Launcher(path.resolve(__dirname, "..")).launch(); 7 | } catch (e) { 8 | throw new Error("Unable to launch application. Try deleting .vscode/launchReactNative.js and restarting vscode."); 9 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "/Users/koalahuang/.vscode/node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-create-fragment.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-create-fragment) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | namespace __Addons { 10 | export function createFragment(object: { [key: string]: ReactNode }): ReactFragment; 11 | } 12 | } 13 | 14 | declare module "react-addons-create-fragment" { 15 | export = __React.__Addons.createFragment; 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-css-transition-group.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-css-transition-group) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | /// 8 | 9 | declare namespace __React { 10 | interface CSSTransitionGroupTransitionName { 11 | enter: string; 12 | enterActive?: string; 13 | leave: string; 14 | leaveActive?: string; 15 | appear?: string; 16 | appearActive?: string; 17 | } 18 | 19 | interface CSSTransitionGroupProps extends TransitionGroupProps { 20 | transitionName: string | CSSTransitionGroupTransitionName; 21 | transitionAppear?: boolean; 22 | transitionAppearTimeout?: number; 23 | transitionEnter?: boolean; 24 | transitionEnterTimeout?: number; 25 | transitionLeave?: boolean; 26 | transitionLeaveTimeout?: number; 27 | } 28 | 29 | type CSSTransitionGroup = ComponentClass; 30 | 31 | namespace __Addons { 32 | export var CSSTransitionGroup: __React.CSSTransitionGroup; 33 | } 34 | } 35 | 36 | declare module "react-addons-css-transition-group" { 37 | var CSSTransitionGroup: __React.CSSTransitionGroup; 38 | type CSSTransitionGroup = __React.CSSTransitionGroup; 39 | export = CSSTransitionGroup; 40 | } 41 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-linked-state-mixin.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-linked-state-mixin) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | interface ReactLink { 10 | value: T; 11 | requestChange(newValue: T): void; 12 | } 13 | 14 | interface LinkedStateMixin extends Mixin { 15 | linkState(key: string): ReactLink; 16 | } 17 | 18 | interface HTMLAttributes { 19 | checkedLink?: ReactLink; 20 | valueLink?: ReactLink; 21 | } 22 | 23 | namespace __Addons { 24 | export var LinkedStateMixin: LinkedStateMixin; 25 | } 26 | } 27 | 28 | declare module "react-addons-linked-state-mixin" { 29 | var LinkedStateMixin: __React.LinkedStateMixin; 30 | type LinkedStateMixin = __React.LinkedStateMixin; 31 | export = LinkedStateMixin; 32 | } 33 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-perf.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-perf) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | interface ComponentPerfContext { 10 | current: string; 11 | owner: string; 12 | } 13 | 14 | interface NumericPerfContext { 15 | [key: string]: number; 16 | } 17 | 18 | interface Measurements { 19 | exclusive: NumericPerfContext; 20 | inclusive: NumericPerfContext; 21 | render: NumericPerfContext; 22 | counts: NumericPerfContext; 23 | writes: NumericPerfContext; 24 | displayNames: { 25 | [key: string]: ComponentPerfContext; 26 | }; 27 | totalTime: number; 28 | } 29 | 30 | namespace __Addons { 31 | namespace Perf { 32 | export function start(): void; 33 | export function stop(): void; 34 | export function printInclusive(measurements: Measurements[]): void; 35 | export function printExclusive(measurements: Measurements[]): void; 36 | export function printWasted(measurements: Measurements[]): void; 37 | export function printDOM(measurements: Measurements[]): void; 38 | export function getLastMeasurements(): Measurements[]; 39 | } 40 | } 41 | } 42 | 43 | declare module "react-addons-perf" { 44 | import Perf = __React.__Addons.Perf; 45 | export = Perf; 46 | } 47 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-pure-render-mixin.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-pure-render-mixin) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | interface PureRenderMixin extends Mixin {} 10 | 11 | namespace __Addons { 12 | export var PureRenderMixin: PureRenderMixin; 13 | } 14 | } 15 | 16 | declare module "react-addons-pure-render-mixin" { 17 | var PureRenderMixin: __React.PureRenderMixin; 18 | type PureRenderMixin = __React.PureRenderMixin; 19 | export = PureRenderMixin; 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-test-utils.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-test-utils) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | interface SyntheticEventData { 10 | altKey?: boolean; 11 | button?: number; 12 | buttons?: number; 13 | clientX?: number; 14 | clientY?: number; 15 | changedTouches?: TouchList; 16 | charCode?: boolean; 17 | clipboardData?: DataTransfer; 18 | ctrlKey?: boolean; 19 | deltaMode?: number; 20 | deltaX?: number; 21 | deltaY?: number; 22 | deltaZ?: number; 23 | detail?: number; 24 | getModifierState?(key: string): boolean; 25 | key?: string; 26 | keyCode?: number; 27 | locale?: string; 28 | location?: number; 29 | metaKey?: boolean; 30 | pageX?: number; 31 | pageY?: number; 32 | relatedTarget?: EventTarget; 33 | repeat?: boolean; 34 | screenX?: number; 35 | screenY?: number; 36 | shiftKey?: boolean; 37 | targetTouches?: TouchList; 38 | touches?: TouchList; 39 | view?: AbstractView; 40 | which?: number; 41 | } 42 | 43 | interface EventSimulator { 44 | (element: Element, eventData?: SyntheticEventData): void; 45 | (component: Component, eventData?: SyntheticEventData): void; 46 | } 47 | 48 | interface MockedComponentClass { 49 | new(): any; 50 | } 51 | 52 | class ShallowRenderer { 53 | getRenderOutput>(): E; 54 | getRenderOutput(): ReactElement; 55 | render(element: ReactElement, context?: any): void; 56 | unmount(): void; 57 | } 58 | 59 | namespace __Addons { 60 | namespace TestUtils { 61 | namespace Simulate { 62 | export var blur: EventSimulator; 63 | export var change: EventSimulator; 64 | export var click: EventSimulator; 65 | export var cut: EventSimulator; 66 | export var doubleClick: EventSimulator; 67 | export var drag: EventSimulator; 68 | export var dragEnd: EventSimulator; 69 | export var dragEnter: EventSimulator; 70 | export var dragExit: EventSimulator; 71 | export var dragLeave: EventSimulator; 72 | export var dragOver: EventSimulator; 73 | export var dragStart: EventSimulator; 74 | export var drop: EventSimulator; 75 | export var focus: EventSimulator; 76 | export var input: EventSimulator; 77 | export var keyDown: EventSimulator; 78 | export var keyPress: EventSimulator; 79 | export var keyUp: EventSimulator; 80 | export var mouseDown: EventSimulator; 81 | export var mouseEnter: EventSimulator; 82 | export var mouseLeave: EventSimulator; 83 | export var mouseMove: EventSimulator; 84 | export var mouseOut: EventSimulator; 85 | export var mouseOver: EventSimulator; 86 | export var mouseUp: EventSimulator; 87 | export var paste: EventSimulator; 88 | export var scroll: EventSimulator; 89 | export var submit: EventSimulator; 90 | export var touchCancel: EventSimulator; 91 | export var touchEnd: EventSimulator; 92 | export var touchMove: EventSimulator; 93 | export var touchStart: EventSimulator; 94 | export var wheel: EventSimulator; 95 | } 96 | 97 | export function renderIntoDocument( 98 | element: DOMElement): Element; 99 | export function renderIntoDocument

( 100 | element: ReactElement

): Component; 101 | export function renderIntoDocument>( 102 | element: ReactElement): C; 103 | 104 | export function mockComponent( 105 | mocked: MockedComponentClass, mockTagName?: string): typeof TestUtils; 106 | 107 | export function isElementOfType( 108 | element: ReactElement, type: ReactType): boolean; 109 | export function isDOMComponent(instance: ReactInstance): boolean; 110 | export function isCompositeComponent(instance: ReactInstance): boolean; 111 | export function isCompositeComponentWithType( 112 | instance: ReactInstance, 113 | type: ComponentClass): boolean; 114 | 115 | export function findAllInRenderedTree( 116 | root: Component, 117 | fn: (i: ReactInstance) => boolean): ReactInstance[]; 118 | 119 | export function scryRenderedDOMComponentsWithClass( 120 | root: Component, 121 | className: string): Element[]; 122 | export function findRenderedDOMComponentWithClass( 123 | root: Component, 124 | className: string): Element; 125 | 126 | export function scryRenderedDOMComponentsWithTag( 127 | root: Component, 128 | tagName: string): Element[]; 129 | export function findRenderedDOMComponentWithTag( 130 | root: Component, 131 | tagName: string): Element; 132 | 133 | export function scryRenderedComponentsWithType

( 134 | root: Component, 135 | type: ComponentClass

): Component[]; 136 | export function scryRenderedComponentsWithType>( 137 | root: Component, 138 | type: ComponentClass): C[]; 139 | 140 | export function findRenderedComponentWithType

( 141 | root: Component, 142 | type: ComponentClass

): Component; 143 | export function findRenderedComponentWithType>( 144 | root: Component, 145 | type: ComponentClass): C; 146 | 147 | export function createRenderer(): ShallowRenderer; 148 | } 149 | } 150 | } 151 | 152 | declare module "react-addons-test-utils" { 153 | import TestUtils = __React.__Addons.TestUtils; 154 | export = TestUtils; 155 | } 156 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-transition-group.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-transition-group) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | 10 | interface TransitionGroupProps { 11 | component?: ReactType; 12 | childFactory?: (child: ReactElement) => ReactElement; 13 | } 14 | 15 | type TransitionGroup = ComponentClass; 16 | 17 | namespace __Addons { 18 | export var TransitionGroup: __React.TransitionGroup; 19 | } 20 | } 21 | 22 | declare module "react-addons-transition-group" { 23 | var TransitionGroup: __React.TransitionGroup; 24 | type TransitionGroup = __React.TransitionGroup; 25 | export = TransitionGroup; 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-addons-update.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-addons-update) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | interface UpdateSpecCommand { 10 | $set?: any; 11 | $merge?: {}; 12 | $apply?(value: any): any; 13 | } 14 | 15 | interface UpdateSpecPath { 16 | [key: string]: UpdateSpec; 17 | } 18 | 19 | type UpdateSpec = UpdateSpecCommand | UpdateSpecPath; 20 | 21 | interface UpdateArraySpec extends UpdateSpecCommand { 22 | $push?: any[]; 23 | $unshift?: any[]; 24 | $splice?: any[][]; 25 | } 26 | 27 | namespace __Addons { 28 | export function update(value: any[], spec: UpdateArraySpec): any[]; 29 | export function update(value: {}, spec: UpdateSpec): any; 30 | } 31 | } 32 | 33 | declare module "react-addons-update" { 34 | export = __React.__Addons.update; 35 | } 36 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-dom.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (react-dom) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare namespace __React { 9 | namespace __DOM { 10 | function findDOMNode(instance: ReactInstance): E; 11 | function findDOMNode(instance: ReactInstance): Element; 12 | 13 | function render

( 14 | element: DOMElement

, 15 | container: Element, 16 | callback?: (element: Element) => any): Element; 17 | function render( 18 | element: ClassicElement

, 19 | container: Element, 20 | callback?: (component: ClassicComponent) => any): ClassicComponent; 21 | function render( 22 | element: ReactElement

, 23 | container: Element, 24 | callback?: (component: Component) => any): Component; 25 | 26 | function unmountComponentAtNode(container: Element): boolean; 27 | 28 | var version: string; 29 | 30 | function unstable_batchedUpdates(callback: (a: A, b: B) => any, a: A, b: B): void; 31 | function unstable_batchedUpdates(callback: (a: A) => any, a: A): void; 32 | function unstable_batchedUpdates(callback: () => any): void; 33 | 34 | function unstable_renderSubtreeIntoContainer

( 35 | parentComponent: Component, 36 | nextElement: DOMElement

, 37 | container: Element, 38 | callback?: (element: Element) => any): Element; 39 | function unstable_renderSubtreeIntoContainer( 40 | parentComponent: Component, 41 | nextElement: ClassicElement

, 42 | container: Element, 43 | callback?: (component: ClassicComponent) => any): ClassicComponent; 44 | function unstable_renderSubtreeIntoContainer( 45 | parentComponent: Component, 46 | nextElement: ReactElement

, 47 | container: Element, 48 | callback?: (component: Component) => any): Component; 49 | } 50 | 51 | namespace __DOMServer { 52 | function renderToString(element: ReactElement): string; 53 | function renderToStaticMarkup(element: ReactElement): string; 54 | var version: string; 55 | } 56 | } 57 | 58 | declare module "react-dom" { 59 | import DOM = __React.__DOM; 60 | export = DOM; 61 | } 62 | 63 | declare module "react-dom/server" { 64 | import DOMServer = __React.__DOMServer; 65 | export = DOMServer; 66 | } 67 | -------------------------------------------------------------------------------- /.vscode/typings/react/react-global.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for React v0.14 (namespace) 2 | // Project: http://facebook.github.io/react/ 3 | // Definitions by: Asana , AssureSign , Microsoft 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | 17 | import React = __React; 18 | import ReactDOM = __React.__DOM; 19 | 20 | declare namespace __React { 21 | export import addons = __React.__Addons; 22 | } 23 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /GoBack.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | TouchableHighlight, 4 | View 5 | } from 'react-native' 6 | 7 | import Icon from 'react-native-vector-icons/Ionicons' 8 | 9 | export default class GoBack extends React.Component { 10 | render () { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | _goBack () { 23 | this.props.navigator.pop() 24 | } 25 | } 26 | 27 | const styles = StyleSheet.create({ 28 | container: { 29 | position: 'absolute', 30 | top: 20, 31 | left: 0 32 | }, 33 | arrow: { 34 | width: 60, 35 | height: 60, 36 | justifyContent: 'center', 37 | alignItems: 'center' 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /Loading.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | ActivityIndicatorIOS, 3 | StyleSheet, 4 | View 5 | } from 'react-native' 6 | 7 | class Loading extends React.Component { 8 | render () { 9 | return ( 10 | 11 | 15 | 16 | ) 17 | } 18 | } 19 | 20 | const styles = StyleSheet.create({ 21 | container: { 22 | flex: 1, 23 | backgroundColor: 'white', 24 | flexDirection: 'column', 25 | justifyContent: 'center' 26 | }, 27 | centerText: { 28 | alignItems: 'center' 29 | }, 30 | spinner: { 31 | width: 50 32 | } 33 | }) 34 | 35 | export default Loading 36 | -------------------------------------------------------------------------------- /Project01-SimpleStopWatch/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | TouchableHighlight, 4 | TouchableOpacity, 5 | View, 6 | Text 7 | } from 'react-native' 8 | 9 | import GoBack from '../GoBack' 10 | import autobind from 'autobind-decorator' 11 | import Icon from 'react-native-vector-icons/Ionicons' 12 | 13 | export const title = '01 - SimpleStopWatch' 14 | export const description = '一个简单的定时器' 15 | 16 | @autobind 17 | export default class SimpleStopWatch extends React.Component { 18 | constructor (props) { 19 | super(props) 20 | this.timerID = null 21 | this.state = { 22 | count: '0.0' 23 | } 24 | } 25 | 26 | componentWillUnmount () { 27 | this._onPause() 28 | this._reset() 29 | } 30 | 31 | render () { 32 | return ( 33 | 34 | 35 | 36 | {this.state.count} 37 | 38 | 39 | 40 | Reset 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ) 55 | } 56 | 57 | _onStart () { 58 | if (this.timerID) return 59 | 60 | this.timerID = setInterval(() => { 61 | const count = this.state.count 62 | this.setState({count: String((Number(count) + 0.1).toFixed(1))}) 63 | }, 100) 64 | } 65 | 66 | _onPause () { 67 | clearInterval(this.timerID) 68 | this.timerID = null 69 | } 70 | 71 | _reset () { 72 | this.setState({count: '0.0'}) 73 | } 74 | } 75 | 76 | const styles = StyleSheet.create({ 77 | container: { 78 | flex: 1, 79 | flexDirection: 'column' 80 | }, 81 | countWrap: { 82 | flex: 0.5, 83 | justifyContent: 'center', 84 | alignItems: 'center', 85 | backgroundColor: '#090123' 86 | }, 87 | reset: { 88 | position: 'absolute', 89 | top: 38, 90 | right: 20 91 | }, 92 | resetText: { 93 | color: '#ffffff' 94 | }, 95 | count: { 96 | fontFamily: 'Avenir Next', 97 | color: '#ffffff', 98 | fontWeight: '100', 99 | fontSize: 80 100 | }, 101 | control: { 102 | flex: 0.5, 103 | flexDirection: 'row' 104 | }, 105 | left: { 106 | flex: 1, 107 | justifyContent: 'center', 108 | alignItems: 'center', 109 | backgroundColor: '#525BFC' 110 | }, 111 | right: { 112 | flex: 1, 113 | justifyContent: 'center', 114 | alignItems: 'center', 115 | backgroundColor: '#66BD09' 116 | } 117 | }) 118 | -------------------------------------------------------------------------------- /Project02-CustomFont/MFJinHei_Noncommercial-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project02-CustomFont/MFJinHei_Noncommercial-Regular.ttf -------------------------------------------------------------------------------- /Project02-CustomFont/MFTongXin_Noncommercial-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project02-CustomFont/MFTongXin_Noncommercial-Regular.ttf -------------------------------------------------------------------------------- /Project02-CustomFont/MFZhiHei_Noncommercial-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project02-CustomFont/MFZhiHei_Noncommercial-Regular.ttf -------------------------------------------------------------------------------- /Project02-CustomFont/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Dimensions, 4 | TouchableHighlight, 5 | View, 6 | Text 7 | } from 'react-native' 8 | 9 | import GoBack from '../GoBack' 10 | import autobind from 'autobind-decorator' 11 | 12 | const {width} = Dimensions.get('window') 13 | 14 | const fontNames = [ 15 | 'MFTongXin_Noncommercial-Regular', 16 | 'MFJinHei_Noncommercial-Regular', 17 | 'MFZhiHei_Noncommercial-Regular' 18 | ] 19 | 20 | const text = ` 21 | 30Days of React Native. 22 | 23 | React Native 将会在2016大放异彩 24 | 25 | 它正在吞噬其他移动开发方式 26 | 27 | 你不需要学习任何Java、OC、Swift 28 | 29 | 它的开发方式是非常先进的,希望iOS能尽快使用上HMR 30 | 31 | 微博 @大P仙森 32 | ` 33 | 34 | export const title = '02 - CustomFont' 35 | export const description = '自定义字体' 36 | 37 | @autobind 38 | export default class SimpleStopWatch extends React.Component { 39 | constructor () { 40 | super() 41 | this.state = { 42 | currentIndex: 0, 43 | currentFontFamily: fontNames[0] 44 | } 45 | } 46 | 47 | render () { 48 | return ( 49 | 50 | 51 | 52 | {text} 53 | 54 | 55 | 56 | 57 | 58 | Change Font 59 | 60 | 61 | 62 | 63 | 64 | ) 65 | } 66 | 67 | _onChangeFont () { 68 | const currentIndex = this.state.currentIndex === fontNames.length - 1 69 | ? 0 70 | : this.state.currentIndex + 1 71 | this.setState({ 72 | currentIndex, 73 | currentFontFamily: fontNames[currentIndex] 74 | }) 75 | } 76 | } 77 | 78 | const styles = StyleSheet.create({ 79 | container: { 80 | flex: 1, 81 | backgroundColor: '#080610', 82 | position: 'relative', 83 | paddingTop: 40 84 | }, 85 | textContainer: { 86 | padding: 10 87 | }, 88 | text: { 89 | lineHeight: 26, 90 | color: '#ffffff' 91 | }, 92 | footer: { 93 | position: 'absolute', 94 | left: 0, 95 | bottom: 40, 96 | width, 97 | justifyContent: 'center', 98 | alignItems: 'center' 99 | }, 100 | footerBtn: { 101 | width: 100, 102 | height: 100, 103 | borderRadius: 50, 104 | justifyContent: 'center', 105 | alignItems: 'center', 106 | backgroundColor: '#DDE20B' 107 | }, 108 | btnText: { 109 | fontSize: 14, 110 | fontWeight: '500', 111 | color: '#080610' 112 | } 113 | }) 114 | -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/VideoPlay.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | AlertIOS, 6 | TouchableOpacity 7 | } from 'react-native' 8 | 9 | import Video from 'react-native-video' 10 | import autobind from 'autobind-decorator' 11 | import GoBack from '../GoBack' 12 | 13 | @autobind 14 | export default class VideoPlay extends React.Component { 15 | constructor () { 16 | super() 17 | this.state = { 18 | rate: 1, 19 | volume: 1, 20 | muted: false, 21 | resizeMode: 'contain', 22 | duration: 0.0, 23 | currentTime: 0.0, 24 | paused: false, 25 | controls: true, 26 | skin: 'native' 27 | } 28 | } 29 | 30 | render () { 31 | return ( 32 | 33 | {this.state.controls ? this._renderNativeSkin() : this._renderCustomSkin()} 34 | 35 | 36 | ) 37 | } 38 | 39 | _renderCustomSkin () { 40 | const flexCompleted = this.getCurrentTimePercentage() * 100 41 | const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100 42 | 43 | return ( 44 | 45 | { this.setState({paused: !this.state.paused}) }}> 46 | 58 | 59 | 60 | 61 | 62 | {this._renderSkinControl('custom')} 63 | {this._renderSkinControl('native')} 64 | {this._renderSkinControl('embed')} 65 | 66 | 67 | 68 | 69 | {this._renderRateControl(0.5)} 70 | {this._renderRateControl(1.0)} 71 | {this._renderRateControl(2.0)} 72 | 73 | 74 | 75 | {this._renderVolumeControl(0.5)} 76 | {this._renderVolumeControl(1)} 77 | {this._renderVolumeControl(1.5)} 78 | 79 | 80 | 81 | {this._renderResizeModeControl('cover')} 82 | {this._renderResizeModeControl('contain')} 83 | {this._renderResizeModeControl('stretch')} 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | ) 96 | } 97 | 98 | _renderNativeSkin () { 99 | const videoStyle = this.state.skin === 'embed' ? styles.nativeVideoControls : styles.fullScreen 100 | 101 | return ( 102 | 103 | 104 | 117 | 118 | 119 | 120 | {this._renderSkinControl('custom')} 121 | {this._renderSkinControl('native')} 122 | {this._renderSkinControl('embed')} 123 | 124 | 125 | 126 | 127 | {this._renderRateControl(0.5)} 128 | {this._renderRateControl(1.0)} 129 | {this._renderRateControl(2.0)} 130 | 131 | 132 | 133 | {this._renderVolumeControl(0.5)} 134 | {this._renderVolumeControl(1)} 135 | {this._renderVolumeControl(1.5)} 136 | 137 | 138 | 139 | {this._renderResizeModeControl('cover')} 140 | {this._renderResizeModeControl('contain')} 141 | {this._renderResizeModeControl('stretch')} 142 | 143 | 144 | 145 | 146 | ) 147 | } 148 | 149 | onLoad (data) { 150 | this.setState({duration: data.duration}) 151 | } 152 | 153 | onProgress (data) { 154 | this.setState({currentTime: data.currentTime}) 155 | } 156 | 157 | getCurrentTimePercentage () { 158 | if (this.state.currentTime > 0) { 159 | return parseFloat(this.state.currentTime) / parseFloat(this.state.duration) 160 | } else { 161 | return 0 162 | } 163 | } 164 | 165 | _renderSkinControl (skin) { 166 | const isSelected = this.state.skin === skin 167 | const selectControls = skin === 'native' || skin === 'embed' 168 | return ( 169 | { 170 | this.setState({ 171 | controls: selectControls, 172 | skin: skin 173 | }) }}> 174 | 175 | {skin} 176 | 177 | 178 | ) 179 | } 180 | 181 | _renderRateControl (rate) { 182 | const isSelected = this.state.rate === rate 183 | 184 | return ( 185 | { this.setState({rate: rate}) }}> 186 | 187 | {rate}x 188 | 189 | 190 | ) 191 | } 192 | 193 | _renderResizeModeControl (resizeMode) { 194 | const isSelected = this.state.resizeMode === resizeMode 195 | 196 | return ( 197 | { this.setState({resizeMode: resizeMode}) }}> 198 | 199 | {resizeMode} 200 | 201 | 202 | ) 203 | } 204 | 205 | _renderVolumeControl (volume) { 206 | const isSelected = this.state.volume === volume 207 | 208 | return ( 209 | { this.setState({volume: volume}) }}> 210 | 211 | {volume * 100}% 212 | 213 | 214 | ) 215 | } 216 | } 217 | 218 | const styles = StyleSheet.create({ 219 | videoContainer: { 220 | flex: 1, 221 | justifyContent: 'center', 222 | alignItems: 'center', 223 | backgroundColor: '#000000' 224 | }, 225 | fullScreen: { 226 | position: 'absolute', 227 | top: 0, 228 | left: 0, 229 | bottom: 0, 230 | right: 0 231 | }, 232 | controls: { 233 | backgroundColor: 'transparent', 234 | borderRadius: 5, 235 | position: 'absolute', 236 | bottom: 44, 237 | left: 4, 238 | right: 4 239 | }, 240 | progress: { 241 | flex: 1, 242 | flexDirection: 'row', 243 | borderRadius: 3, 244 | overflow: 'hidden' 245 | }, 246 | innerProgressCompleted: { 247 | height: 20, 248 | backgroundColor: '#cccccc' 249 | }, 250 | innerProgressRemaining: { 251 | height: 20, 252 | backgroundColor: '#2C2C2C' 253 | }, 254 | generalControls: { 255 | flex: 1, 256 | flexDirection: 'row', 257 | overflow: 'hidden', 258 | paddingBottom: 10 259 | }, 260 | skinControl: { 261 | flex: 1, 262 | flexDirection: 'row', 263 | justifyContent: 'center' 264 | }, 265 | rateControl: { 266 | flex: 1, 267 | flexDirection: 'row', 268 | justifyContent: 'center' 269 | }, 270 | volumeControl: { 271 | flex: 1, 272 | flexDirection: 'row', 273 | justifyContent: 'center' 274 | }, 275 | resizeModeControl: { 276 | flex: 1, 277 | flexDirection: 'row', 278 | alignItems: 'center', 279 | justifyContent: 'center' 280 | }, 281 | controlOption: { 282 | alignSelf: 'center', 283 | fontSize: 11, 284 | color: 'white', 285 | paddingLeft: 2, 286 | paddingRight: 2, 287 | lineHeight: 12 288 | }, 289 | nativeVideoControls: { 290 | top: 184, 291 | height: 300 292 | } 293 | }) 294 | -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/emoji.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/emoji.mp4 -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/playBtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/playBtn.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/playBtn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/playBtn@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/playBtn@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/playBtn@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/uie_thumb_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/uie_thumb_big.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/uie_thumb_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/uie_thumb_normal@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/uie_thumb_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/uie_thumb_selected@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot01.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot01@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot01@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot01@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot01@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot02.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot02@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot02@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot02@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot02@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot03.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot03@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot03@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot03@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot03@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot04.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot04@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot04@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot04@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot04@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot05.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot05@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot05@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot05@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot05@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot06.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot06@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot06@2x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/images/videoScreenshot06@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project03-PlayLocalVideo/images/videoScreenshot06@3x.png -------------------------------------------------------------------------------- /Project03-PlayLocalVideo/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | Image, 6 | Navigator, 7 | ScrollView, 8 | ListView, 9 | Dimensions, 10 | TouchableHighlight 11 | } from 'react-native' 12 | 13 | import autobind from 'autobind-decorator' 14 | import VideoPlay from './VideoPlay' 15 | import GoBack from '../GoBack' 16 | 17 | const {width} = Dimensions.get('window') 18 | 19 | const video = [ 20 | {image: require('./images/videoScreenshot01.png'), video: './emoji', title: 'Introduce 3DS Mario', source: 'Youtube - 06:32'}, 21 | {image: require('./images/videoScreenshot02.png'), video: './emoji', title: 'Emoji Among Us', source: 'Vimeo - 3:34'}, 22 | {image: require('./images/videoScreenshot03.png'), video: './emoji', title: 'Seals Documentary', source: 'Vine - 00:06'}, 23 | {image: require('./images/videoScreenshot04.png'), video: './emoji', title: 'Adventure Time', source: 'Youtube - 02:39'}, 24 | {image: require('./images/videoScreenshot05.png'), video: './emoji', title: 'Facebook HQ', source: 'Facebook - 10:20'}, 25 | {image: require('./images/videoScreenshot06.png'), video: './emoji', title: 'Lijiang Lugu Lake', source: 'Allen - 20:30'} 26 | ] 27 | 28 | export const title = '03 - PlayLocalVideo' 29 | export const description = '播放本地视频' 30 | export default class PlayLocalVideo extends React.Component { 31 | render () { 32 | return ( 33 | 34 | 35 | 36 | 37 | ) 38 | } 39 | } 40 | 41 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 42 | 43 | @autobind 44 | class VideoList extends React.Component { 45 | constructor () { 46 | super() 47 | this.state = { 48 | dataSource: ds.cloneWithRows(video) 49 | } 50 | } 51 | 52 | render () { 53 | return ( 54 | 55 | 59 | 60 | ) 61 | } 62 | 63 | _renderRow (rowData, sectionID, rowID) { 64 | return ( 65 | 66 | this._playVideo(rowData)}> 67 | 68 | 71 | 72 | 73 | 74 | {rowData.title} 75 | {rowData.source} 76 | 77 | 78 | 79 | 80 | ) 81 | } 82 | 83 | _playVideo (rowData) { 84 | this.props.navigator.push({ 85 | title: rowData.title, 86 | component: VideoPlay, 87 | passProps: { 88 | video: rowData.video, 89 | navigator: this.props.navigator 90 | }, 91 | SceneConfigs: Navigator.SceneConfigs.FloatFromBottom 92 | }) 93 | } 94 | } 95 | 96 | const styles = StyleSheet.create({ 97 | container: { 98 | flex: 1, 99 | backgroundColor: '#333333' 100 | }, 101 | itemContainer: { 102 | flex: 1, 103 | position: 'relative' 104 | }, 105 | image: { 106 | flex: 1, 107 | resizeMode: 'contain', 108 | justifyContent: 'center', 109 | alignItems: 'center' 110 | }, 111 | playBtn: { 112 | 113 | }, 114 | textContainer: { 115 | width, 116 | height: 60, 117 | position: 'absolute', 118 | bottom: 0, 119 | left: 0, 120 | alignItems: 'center', 121 | justifyContent: 'center' 122 | }, 123 | imageTitle: { 124 | fontFamily: 'Avenir Next', 125 | color: '#ffffff', 126 | fontWeight: '700', 127 | fontSize: 18, 128 | backgroundColor: 'transparent', 129 | marginBottom: 5 130 | }, 131 | imageTime: { 132 | color: '#999999' 133 | } 134 | }) 135 | -------------------------------------------------------------------------------- /Project04-SnapChatMenu/images/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project04-SnapChatMenu/images/left.png -------------------------------------------------------------------------------- /Project04-SnapChatMenu/images/left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project04-SnapChatMenu/images/left@2x.png -------------------------------------------------------------------------------- /Project04-SnapChatMenu/images/right.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project04-SnapChatMenu/images/right.jpg -------------------------------------------------------------------------------- /Project04-SnapChatMenu/images/right@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project04-SnapChatMenu/images/right@2x.jpg -------------------------------------------------------------------------------- /Project04-SnapChatMenu/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Dimensions, 4 | StatusBar, 5 | Image, 6 | View, 7 | TouchableOpacity 8 | } from 'react-native' 9 | 10 | import GoBack from '../GoBack' 11 | import autobind from 'autobind-decorator' 12 | import Swiper from 'react-native-swiper' 13 | import Camera from 'react-native-camera' 14 | import Icon from 'react-native-vector-icons/Ionicons' 15 | 16 | const { width, height } = Dimensions.get('window') 17 | 18 | export const title = '04 - SnapChatMenu' 19 | export const description = 'snapchat视频聊天' 20 | 21 | @autobind 22 | export default class SnapChatMenu extends React.Component { 23 | render () { 24 | return ( 25 | 26 | 51 | ) 52 | } 53 | 54 | _takePicture () { 55 | this.camera.capture() 56 | .then((data) => console.log(data)) 57 | .catch(err => console.error(err)) 58 | } 59 | } 60 | 61 | const styles = StyleSheet.create({ 62 | container: { 63 | flex: 1 64 | }, 65 | slide1: { 66 | flex: 1, 67 | justifyContent: 'center', 68 | alignItems: 'center', 69 | backgroundColor: '#9DD6EB' 70 | }, 71 | slide2: { 72 | flex: 1, 73 | justifyContent: 'center', 74 | alignItems: 'center', 75 | backgroundColor: '#97CAE5' 76 | }, 77 | slide3: { 78 | flex: 1, 79 | justifyContent: 'center', 80 | alignItems: 'center', 81 | backgroundColor: '#92BBD9' 82 | }, 83 | image: { 84 | width, 85 | resizeMode: 'contain' 86 | }, 87 | text: { 88 | color: '#fff', 89 | fontSize: 30, 90 | fontWeight: 'bold' 91 | }, 92 | preview: { 93 | flex: 1, 94 | justifyContent: 'flex-end', 95 | alignItems: 'center', 96 | height, 97 | width 98 | }, 99 | capture: { 100 | flex: 0, 101 | justifyContent: 'center', 102 | alignItems: 'center', 103 | backgroundColor: '#fff', 104 | borderRadius: 50, 105 | width: 85, 106 | height: 85 107 | } 108 | }) 109 | -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/IMG_1517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/IMG_1517.png -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/blue.png -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/bodyline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/bodyline.png -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/darkvarder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/darkvarder.png -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/dudu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/dudu.jpg -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/hello.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/hello.jpg -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/hhhhh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/hhhhh.jpg -------------------------------------------------------------------------------- /Project05-CarouselEffect/images/wave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project05-CarouselEffect/images/wave.jpg -------------------------------------------------------------------------------- /Project05-CarouselEffect/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Dimensions, 4 | ListView, 5 | Image, 6 | Text, 7 | View 8 | } from 'react-native' 9 | 10 | import GoBack from '../GoBack' 11 | import autobind from 'autobind-decorator' 12 | import { BlurView } from 'react-native-blur' 13 | 14 | const { width } = Dimensions.get('window') 15 | 16 | export const title = '05 - CarouselEffect' 17 | export const description = '轮播图效果' 18 | 19 | const imageList = [ 20 | {image: require('./images/hello.jpg'), text: 'Hello there, i miss u.'}, 21 | {image: require('./images/dudu.jpg'), text: '🐳🐳🐳🐳🐳'}, 22 | {image: require('./images/bodyline.png'), text: 'Training like this, #bodyline'}, 23 | {image: require('./images/wave.jpg'), text: 'I\'m hungry, indeed.'}, 24 | {image: require('./images/darkvarder.png'), text: 'Dark Varder, #emoji'}, 25 | {image: require('./images/hhhhh.jpg'), text: 'I have no idea, bitch'} 26 | ] 27 | 28 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 29 | 30 | @autobind 31 | export default class CarouselEffect extends React.Component { 32 | constructor () { 33 | super() 34 | this.state = { 35 | dataSource: ds.cloneWithRows(imageList) 36 | } 37 | } 38 | 39 | render () { 40 | return ( 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | ) 57 | } 58 | 59 | _renderRow (rowData, sectionID, rowID) { 60 | const isLast = Number(rowID) === imageList.length - 1 61 | return ( 62 | 63 | 64 | 65 | {rowData.text} 66 | 67 | 68 | 69 | ) 70 | } 71 | } 72 | 73 | const styles = StyleSheet.create({ 74 | container: { 75 | flex: 1 76 | }, 77 | listContainer: { 78 | flex: 1, 79 | justifyContent: 'center' 80 | }, 81 | listContent: { 82 | width, 83 | height: 450 84 | }, 85 | imageItem: { 86 | position: 'relative', 87 | marginLeft: 20, 88 | width: 300, 89 | height: 400, 90 | borderRadius: 7, 91 | overflow: 'hidden' 92 | }, 93 | lastImage: { 94 | marginRight: 20 95 | }, 96 | image: { 97 | width: 300, 98 | height: 400 99 | }, 100 | textContainer: { 101 | position: 'absolute', 102 | bottom: 0, 103 | left: 0, 104 | width: 300, 105 | height: 60, 106 | overflow: 'hidden', 107 | paddingLeft: 15 108 | }, 109 | text: { 110 | fontSize: 16, 111 | color: '#333333', 112 | lineHeight: 40 113 | } 114 | }) 115 | -------------------------------------------------------------------------------- /Project06-FindMyLocation/images/1-Eb_0OvtcxJXHZ7-IOoBsaQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project06-FindMyLocation/images/1-Eb_0OvtcxJXHZ7-IOoBsaQ.png -------------------------------------------------------------------------------- /Project06-FindMyLocation/images/Find_my_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project06-FindMyLocation/images/Find_my_location.png -------------------------------------------------------------------------------- /Project06-FindMyLocation/images/Find_my_location@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project06-FindMyLocation/images/Find_my_location@2x.png -------------------------------------------------------------------------------- /Project06-FindMyLocation/images/Find_my_location@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project06-FindMyLocation/images/Find_my_location@3x.png -------------------------------------------------------------------------------- /Project06-FindMyLocation/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | View, 3 | Text, 4 | Image, 5 | StyleSheet, 6 | Dimensions, 7 | TouchableHighlight 8 | } from 'react-native' 9 | 10 | import autobind from 'autobind-decorator' 11 | import { BlurView } from 'react-native-blur' 12 | import GoBack from '../GoBack' 13 | 14 | const { width, height } = Dimensions.get('window') 15 | const vw = width / 100 16 | const vh = height / 100 17 | 18 | export const title = '06 - FindMyLocation' 19 | export const description = '我的地理位置' 20 | 21 | @autobind 22 | export default class FindMyLocation extends React.Component { 23 | constructor () { 24 | super() 25 | this.state = { 26 | myLocation: 'My Location' 27 | } 28 | } 29 | 30 | render () { 31 | return ( 32 | 33 | 34 | 35 | {this.state.myLocation} 36 | 37 | 38 | this._getMyLocation()} underlayColor={'transparent'}> 39 | 40 | 43 | Find My Location 44 | 45 | 46 | 47 | 48 | 49 | 50 | ) 51 | } 52 | 53 | _getMyLocation () { 54 | navigator.geolocation.getCurrentPosition( 55 | (position) => { 56 | const myLocation = JSON.stringify(position) 57 | this.setState({myLocation}) 58 | setTimeout(() => { 59 | this.setState({myLocation: '目前没有获取城市好的实现'}) 60 | }, 1000) 61 | }, 62 | (error) => alert(error.message), 63 | {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000} 64 | ) 65 | } 66 | } 67 | 68 | const styles = StyleSheet.create({ 69 | container: { 70 | flex: 1, 71 | alignItems: 'center', 72 | width 73 | }, 74 | myLocation: { 75 | marginTop: 80, 76 | width: 90 * vw, 77 | height: 60, 78 | backgroundColor: '#1B1323', 79 | justifyContent: 'center', 80 | alignItems: 'center', 81 | borderRadius: 5 82 | }, 83 | myLocationText: { 84 | color: '#ffffff' 85 | }, 86 | buttonContainer: { 87 | width, 88 | position: 'absolute', 89 | bottom: 10, 90 | left: 0, 91 | justifyContent: 'center', 92 | alignItems: 'center' 93 | }, 94 | buttonContent: { 95 | width: 80 * vw, 96 | height: 10 * vh, 97 | alignItems: 'center' 98 | }, 99 | buttonImage: { 100 | width: 80 * vw, 101 | height: 10 * vh 102 | }, 103 | buttonText: { 104 | marginTop: -44, 105 | fontSize: 14, 106 | color: '#ffffff' 107 | } 108 | }) 109 | -------------------------------------------------------------------------------- /Project07-PullToRefresh/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | ScrollView, 3 | StyleSheet, 4 | RefreshControl, 5 | View, 6 | Text, 7 | TouchableWithoutFeedback 8 | } from 'react-native' 9 | 10 | import autobind from 'autobind-decorator' 11 | import GoBack from '../GoBack' 12 | 13 | const favoriteEmoji = ['🤗🤗🤗🤗🤗', '😅😅😅😅😅', '😆😆😆😆😆'] 14 | const newFavoriteEmoji = ['🏃🏃🏃🏃🏃', '💩💩💩💩💩', '👸👸👸👸👸', '🤗🤗🤗🤗🤗', '😅😅😅😅😅', '😆😆😆😆😆'] 15 | 16 | export const title = '07 - PullToRefresh' 17 | export const description = '下拉刷新' 18 | 19 | @autobind 20 | export default class PullToRefresh extends React.Component { 21 | constructor () { 22 | super() 23 | this.state = { 24 | isRefreshing: false, 25 | loaded: 0, 26 | rowData: favoriteEmoji.map( 27 | (val, i) => ({emoji: val}) 28 | ) 29 | } 30 | } 31 | 32 | render () { 33 | const rows = this.state.rowData.map((row, i) => { 34 | return 35 | }) 36 | 37 | const now = new Date().toString() 38 | 39 | return ( 40 | 41 | 53 | }> 54 | {rows} 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | _onRefresh () { 62 | this.setState({isRefreshing: true}) 63 | setTimeout(() => { 64 | const rowData = newFavoriteEmoji 65 | .map((val, i) => ({ 66 | emoji: val 67 | })) 68 | .concat(this.state.rowData) 69 | 70 | this.setState({ 71 | loaded: this.state.loaded + 10, 72 | isRefreshing: false, 73 | rowData: rowData 74 | }) 75 | }, 5000) 76 | } 77 | } 78 | 79 | class Row extends React.Component { 80 | render () { 81 | return ( 82 | 83 | 84 | {this.props.emoji} 85 | 86 | 87 | ) 88 | } 89 | } 90 | 91 | const styles = StyleSheet.create({ 92 | scrollview: { 93 | flex: 1, 94 | backgroundColor: '#16141B' 95 | }, 96 | row: { 97 | padding: 20, 98 | margin: 5, 99 | justifyContent: 'center', 100 | alignItems: 'center' 101 | }, 102 | text: { 103 | fontSize: 50 104 | }, 105 | refresh: { 106 | backgroundColor: '#333333' 107 | } 108 | }) 109 | -------------------------------------------------------------------------------- /Project08-RandomGradientColorMusic/Ecstasy.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project08-RandomGradientColorMusic/Ecstasy.mp3 -------------------------------------------------------------------------------- /Project08-RandomGradientColorMusic/images/music play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project08-RandomGradientColorMusic/images/music play.png -------------------------------------------------------------------------------- /Project08-RandomGradientColorMusic/images/music play@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project08-RandomGradientColorMusic/images/music play@2x.png -------------------------------------------------------------------------------- /Project08-RandomGradientColorMusic/images/music play@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project08-RandomGradientColorMusic/images/music play@3x.png -------------------------------------------------------------------------------- /Project08-RandomGradientColorMusic/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | TouchableHighlight 5 | } from 'react-native' 6 | 7 | import GoBack from '../GoBack' 8 | import autobind from 'autobind-decorator' 9 | import LinearGradient from 'react-native-linear-gradient' 10 | import Sound from 'react-native-sound' 11 | import Icon from 'react-native-vector-icons/Ionicons' 12 | 13 | export const title = '08 - RandomGradientColorMusic' 14 | export const description = '音乐随机背景渐变' 15 | 16 | @autobind 17 | export default class RandomGradientColorMusic extends React.Component { 18 | constructor () { 19 | super() 20 | this.state = { 21 | musicUrl: './Ecstasy.mp3', 22 | bgColor: this._randomColor(), 23 | colors: [ 24 | 'rgba(125, 125, 125, 0.2)', 25 | 'rgba(255, 0, 0, 0.2)', 26 | 'rgba(0, 255, 0, 0.2)', 27 | 'rgba(0, 0, 255, 0.2)', 28 | 'rgba(110, 110, 110, 0.2)' 29 | ] 30 | } 31 | } 32 | 33 | componentWillUnmount () { 34 | this._stop() 35 | } 36 | 37 | render () { 38 | return ( 39 | 40 | 46 | this._onPlay()} underlayColor='transparent'> 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ) 55 | } 56 | 57 | _onPlay () { 58 | clearInterval(this.timerID) 59 | 60 | this._playMusic() 61 | 62 | this.timerID = setInterval(() => { 63 | this.setState({ 64 | bgColor: this._randomColor() 65 | }) 66 | }, 200) 67 | } 68 | 69 | _playMusic () { 70 | const self = this 71 | 72 | if (!this.music) { 73 | this.music = new Sound('Ecstasy.mp3', Sound.MAIN_BUNDLE, (error) => { 74 | if (error) { 75 | console.log('failed to load the sound', error) 76 | } else { // loaded successfully 77 | console.log('duration in seconds: ' + self.music._duration + 78 | 'number of channels: ' + self.music._numberOfChannels) 79 | // 无线循环播放 80 | self.music.setNumberOfLoops(-1).play() 81 | } 82 | }) 83 | } else { 84 | this.music.play() 85 | } 86 | } 87 | 88 | _stop () { 89 | clearInterval(this.timerID) 90 | this.timerID = null 91 | if (this.music) { 92 | this.music.release() 93 | this.music = null 94 | } 95 | } 96 | 97 | _randomColor () { 98 | return `rgba(${this._randomColorValue()}, ${this._randomColorValue()}, ${this._randomColorValue()}, 1)` 99 | } 100 | 101 | _randomColorValue () { 102 | return Math.floor(Math.random() * 256) 103 | } 104 | } 105 | 106 | const styles = StyleSheet.create({ 107 | container: { 108 | flex: 1 109 | }, 110 | linearGradient: { 111 | flex: 1, 112 | paddingLeft: 15, 113 | paddingRight: 15, 114 | justifyContent: 'center', 115 | alignItems: 'center' 116 | }, 117 | buttton: { 118 | justifyContent: 'center', 119 | alignItems: 'center', 120 | width: 100, 121 | height: 100, 122 | borderRadius: 50, 123 | backgroundColor: 'rgba(256,256,256,0.2)' 124 | } 125 | }) 126 | -------------------------------------------------------------------------------- /Project09-ImageScroller/ImageBaseScroller.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | ScrollView, 3 | Platform, 4 | Image, 5 | View 6 | } from 'react-native' 7 | 8 | import autobind from 'autobind-decorator' 9 | 10 | @autobind 11 | export default class ImageBaseScroller extends React.Component { 12 | componentWillMount () { 13 | const widthScale = this.props.size.width / this.props.width 14 | const heightScale = this.props.size.height / this.props.height 15 | const minimumScale = Math.min(widthScale, heightScale) 16 | 17 | this._minimumZoomScale = Math.floor(minimumScale) 18 | this._maximumZoomScale = 3.0 19 | 20 | this._horizontal = widthScale > heightScale 21 | 22 | if (this._horizontal) { 23 | this._scaledImageSize = { 24 | width: this.props.width * heightScale, 25 | height: this.props.size.height 26 | } 27 | } else { 28 | this._scaledImageSize = { 29 | width: this.props.size.width, 30 | height: this.props.height * widthScale 31 | } 32 | if (Platform.OS === 'android') { 33 | // hack to work around Android ScrollView a) not supporting zoom, and 34 | // b) not supporting vertical scrolling when nested inside another 35 | // vertical ScrollView (which it is, when displayed inside UIExplorer) 36 | this._scaledImageSize.width *= 2 37 | this._scaledImageSize.height *= 2 38 | } 39 | } 40 | } 41 | 42 | render () { 43 | return ( 44 | 45 | 56 | 60 | 61 | 62 | ) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Project09-ImageScroller/images/Steve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project09-ImageScroller/images/Steve.png -------------------------------------------------------------------------------- /Project09-ImageScroller/images/Steve@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project09-ImageScroller/images/Steve@2x.png -------------------------------------------------------------------------------- /Project09-ImageScroller/images/Steve@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project09-ImageScroller/images/Steve@3x.png -------------------------------------------------------------------------------- /Project09-ImageScroller/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Dimensions, 4 | Image, 5 | View 6 | } from 'react-native' 7 | 8 | import resolveAssetSource from 'resolveAssetSource' 9 | import autobind from 'autobind-decorator' 10 | import GoBack from '../GoBack' 11 | import { BlurView } from 'react-native-blur' 12 | 13 | import ImageBaseScroller from './ImageBaseScroller' 14 | 15 | const { width, height } = Dimensions.get('window') 16 | 17 | export const title = '09 - ImageScroller' 18 | export const description = '图片滚动' 19 | 20 | const source = require('./images/Steve.png') 21 | const image = resolveAssetSource(source) 22 | 23 | @autobind 24 | export default class ImageScroller extends React.Component { 25 | render () { 26 | return ( 27 | 28 | 29 | 30 | {image.width && 31 | 38 | } 39 | 40 | 41 | 42 | 43 | ) 44 | } 45 | } 46 | 47 | const styles = StyleSheet.create({ 48 | container: { 49 | flex: 1, 50 | width 51 | }, 52 | blurContainer: { 53 | flex: 1, 54 | justifyContent: 'center', 55 | alignItems: 'center' 56 | }, 57 | imageContainer: { 58 | flex: 1, 59 | alignSelf: 'stretch' 60 | }, 61 | imageCropper: { 62 | flex: 1, 63 | alignSelf: 'center' 64 | } 65 | }) 66 | -------------------------------------------------------------------------------- /Project10-VideoBackground/images/LaunchImage-800-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/LaunchImage-800-667h@2x.png -------------------------------------------------------------------------------- /Project10-VideoBackground/images/LaunchImage-800-Portrait-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/LaunchImage-800-Portrait-736h@3x.png -------------------------------------------------------------------------------- /Project10-VideoBackground/images/ambience-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/ambience-1.jpg -------------------------------------------------------------------------------- /Project10-VideoBackground/images/login-secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/login-secondary-logo.png -------------------------------------------------------------------------------- /Project10-VideoBackground/images/login-secondary-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/login-secondary-logo@2x.png -------------------------------------------------------------------------------- /Project10-VideoBackground/images/login-secondary-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/images/login-secondary-logo@3x.png -------------------------------------------------------------------------------- /Project10-VideoBackground/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | Image, 6 | Dimensions, 7 | TouchableHighlight 8 | } from 'react-native' 9 | 10 | import autobind from 'autobind-decorator' 11 | import Video from 'react-native-video' 12 | import GoBack from '../GoBack' 13 | 14 | const { width } = Dimensions.get('window') 15 | const vw = width / 100 16 | 17 | export const title = '10 - VideoBackground' 18 | export const description = '背景视频' 19 | 20 | @autobind 21 | export default class VideoBackground extends React.Component { 22 | constructor () { 23 | super() 24 | this.state = { 25 | video: './moments', 26 | rate: 1, 27 | volume: 1, 28 | muted: false, 29 | resizeMode: 'contain', 30 | duration: 0.0, 31 | currentTime: 0.0, 32 | paused: false, 33 | controls: true, 34 | skin: 'native' 35 | } 36 | } 37 | 38 | render () { 39 | return ( 40 | 41 | 67 | ) 68 | } 69 | } 70 | 71 | const styles = StyleSheet.create({ 72 | container: { 73 | flex: 1 74 | }, 75 | fullScreen: { 76 | position: 'absolute', 77 | top: 0, 78 | left: 0, 79 | bottom: 0, 80 | right: 0 81 | }, 82 | titleContainer: { 83 | width, 84 | position: 'absolute', 85 | left: 0, 86 | top: 60, 87 | alignItems: 'center' 88 | }, 89 | title: { 90 | width: 80 * vw 91 | }, 92 | buttonContainer: { 93 | width, 94 | position: 'absolute', 95 | left: 0, 96 | bottom: 30, 97 | alignItems: 'center' 98 | }, 99 | button: { 100 | height: 50, 101 | width: 320, 102 | borderRadius: 5, 103 | marginTop: 20, 104 | justifyContent: 'center', 105 | alignItems: 'center' 106 | }, 107 | btnLogin: { 108 | backgroundColor: 'green' 109 | }, 110 | btnLoginText: { 111 | fontSize: 14, 112 | color: '#ffffff' 113 | }, 114 | btnSignup: { 115 | backgroundColor: '#ffffff' 116 | }, 117 | btnSignupText: { 118 | fontSize: 16, 119 | color: 'green' 120 | } 121 | }) 122 | -------------------------------------------------------------------------------- /Project10-VideoBackground/moments.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project10-VideoBackground/moments.mp4 -------------------------------------------------------------------------------- /Project11-ClearTableViewCell/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | ListView, 4 | View, 5 | Text 6 | } from 'react-native' 7 | 8 | import autobind from 'autobind-decorator' 9 | import GoBack from '../GoBack' 10 | import LinearGradient from 'react-native-linear-gradient' 11 | 12 | export const title = '11 - ClearTableViewCell' 13 | export const description = 'Table列表' 14 | 15 | const ds = new ListView.DataSource({ 16 | rowHasChanged: (r1, r2) => r1 !== r2 17 | }) 18 | 19 | const tableData = [ 20 | 'Read 3 article on Medium', 21 | 'Cleanup bedroom', 22 | 'Go for a run', 23 | 'Hit the gym', 24 | 'Build another swift project', 25 | 'Movement training', 26 | 'Fix the layout problem of a client project', 27 | 'Write the experience of #30daysSwift', 28 | 'Inbox Zero', 29 | 'Booking the ticket to Chengdu', 30 | 'Test the Adobe Project Comet', 31 | 'Hop on a call to mom' 32 | ] 33 | 34 | @autobind 35 | export default class ClearTableViewCell extends React.Component { 36 | constructor () { 37 | super() 38 | this.state = { 39 | dataSource: ds.cloneWithRows(tableData) 40 | } 41 | } 42 | 43 | render () { 44 | return ( 45 | 46 | 50 | 51 | 52 | ) 53 | } 54 | 55 | _renderRow (rowData, sectionID, rowID) { 56 | const bgColor = this._getCellBgColor(rowID) 57 | return ( 58 | 59 | 71 | {rowData} 72 | 73 | 74 | ) 75 | } 76 | 77 | _getCellBgColor (index) { 78 | const totalCount = tableData.length - 1 79 | const color = Math.floor(256 * (Number(index) / totalCount) * 0.6) 80 | return `rgba(255, ${color}, 0, 1.0)` 81 | } 82 | } 83 | 84 | const styles = StyleSheet.create({ 85 | container: { 86 | flex: 1, 87 | backgroundColor: '#333333' 88 | }, 89 | linearGradient: { 90 | flex: 1, 91 | paddingLeft: 15, 92 | paddingRight: 15, 93 | justifyContent: 'center', 94 | alignItems: 'flex-start' 95 | }, 96 | tabelCell: { 97 | height: 60 98 | }, 99 | text: { 100 | color: '#ffffff', 101 | backgroundColor: 'transparent', 102 | fontFamily: 'Avenir Next', 103 | fontSize: 18 104 | } 105 | }) 106 | -------------------------------------------------------------------------------- /Project12-LoginAnimation/Login.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | View, 3 | Text, 4 | TextInput, 5 | Easing, 6 | Animated, 7 | StyleSheet, 8 | Dimensions, 9 | TouchableHighlight 10 | } from 'react-native' 11 | 12 | import autobind from 'autobind-decorator' 13 | import GoBack from '../GoBack' 14 | 15 | const { width } = Dimensions.get('window') 16 | const vw = width / 100 17 | 18 | @autobind 19 | export default class Login extends React.Component { 20 | constructor () { 21 | super() 22 | this.state = { 23 | marginValue1: new Animated.Value(-1000), 24 | marginValue2: new Animated.Value(-1000), 25 | marginValue3: new Animated.Value(-1000), 26 | buttonSize: new Animated.Value(150) 27 | } 28 | } 29 | 30 | componentDidMount () { 31 | Animated.timing(this.state.marginValue1, { 32 | toValue: 0, // 目标值 33 | duration: 800, // 动画时间 34 | easing: Easing.easeOut // 缓动函数 35 | }).start() 36 | 37 | Animated.timing(this.state.marginValue2, { 38 | toValue: 0, // 目标值 39 | duration: 800, // 动画时间 40 | delay: 100, 41 | easing: Easing.easeOut // 缓动函数 42 | }).start() 43 | 44 | Animated.timing(this.state.marginValue3, { 45 | toValue: 0, // 目标值 46 | duration: 800, // 动画时间 47 | delay: 200, 48 | easing: Easing.easeOut // 缓动函数 49 | }).start() 50 | } 51 | 52 | render () { 53 | return ( 54 | 55 | 56 | Welcome 57 | 58 | 59 | 60 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | 79 | 80 | Login 81 | 82 | 83 | 84 | 85 | 86 | ) 87 | } 88 | 89 | _onBttonAniamte () { 90 | Animated.spring(this.state.buttonSize, { 91 | toValue: 200, // 目标值 92 | friction: 2 // Bouncier spring 93 | }).start() 94 | } 95 | } 96 | 97 | const styles = StyleSheet.create({ 98 | container: { 99 | flex: 1, 100 | backgroundColor: 'green' 101 | }, 102 | title: { 103 | marginTop: 36, 104 | marginBottom: 20, 105 | justifyContent: 'center', 106 | alignItems: 'center' 107 | }, 108 | titleText: { 109 | fontSize: 16, 110 | color: '#ffffff' 111 | }, 112 | input: { 113 | height: 40, 114 | marginTop: 10, 115 | marginBottom: 20, 116 | justifyContent: 'center', 117 | alignItems: 'center' 118 | }, 119 | iptText: { 120 | height: 50, 121 | width: 90 * vw, 122 | paddingLeft: 10, 123 | paddingRight: 10, 124 | borderRadius: 5, 125 | backgroundColor: 'white' 126 | }, 127 | button: { 128 | height: 50, 129 | width: 150, 130 | borderRadius: 5, 131 | marginTop: 20, 132 | justifyContent: 'center', 133 | alignItems: 'center', 134 | backgroundColor: '#136E03' 135 | }, 136 | buttonText: { 137 | fontSize: 14, 138 | color: '#ffffff' 139 | } 140 | }) 141 | -------------------------------------------------------------------------------- /Project12-LoginAnimation/images/Back-icon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project12-LoginAnimation/images/Back-icon.pdf -------------------------------------------------------------------------------- /Project12-LoginAnimation/images/ambience.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project12-LoginAnimation/images/ambience.jpg -------------------------------------------------------------------------------- /Project12-LoginAnimation/images/login-secondary-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project12-LoginAnimation/images/login-secondary-logo.png -------------------------------------------------------------------------------- /Project12-LoginAnimation/images/login-secondary-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project12-LoginAnimation/images/login-secondary-logo@2x.png -------------------------------------------------------------------------------- /Project12-LoginAnimation/images/login-secondary-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project12-LoginAnimation/images/login-secondary-logo@3x.png -------------------------------------------------------------------------------- /Project12-LoginAnimation/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | Image, 6 | Dimensions, 7 | TouchableHighlight 8 | } from 'react-native' 9 | 10 | import autobind from 'autobind-decorator' 11 | import Login from './Login' 12 | import GoBack from '../GoBack' 13 | 14 | const { width } = Dimensions.get('window') 15 | const vw = width / 100 16 | 17 | export const title = '12 - LoginAnimation' 18 | export const description = '登录动画' 19 | 20 | @autobind 21 | export default class LoginAnimation extends React.Component { 22 | render () { 23 | return ( 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | Sign up 35 | 36 | 37 | this._onPress()} underlayColor='transparent'> 38 | 39 | Login 40 | 41 | 42 | 43 | 44 | 45 | ) 46 | } 47 | 48 | _onPress () { 49 | this.props.navigator.push({ 50 | title: '登录', 51 | component: Login 52 | }) 53 | } 54 | } 55 | 56 | const styles = StyleSheet.create({ 57 | container: { 58 | flex: 1, 59 | backgroundColor: 'green' 60 | }, 61 | fullScreen: { 62 | position: 'absolute', 63 | top: 0, 64 | left: 0, 65 | bottom: 0, 66 | right: 0 67 | }, 68 | titleContainer: { 69 | width, 70 | position: 'absolute', 71 | left: 0, 72 | top: 60, 73 | alignItems: 'center' 74 | }, 75 | title: { 76 | width: 80 * vw 77 | }, 78 | buttonContainer: { 79 | width, 80 | position: 'absolute', 81 | left: 0, 82 | bottom: 30, 83 | alignItems: 'center' 84 | }, 85 | button: { 86 | height: 50, 87 | width: 320, 88 | borderRadius: 5, 89 | marginTop: 20, 90 | justifyContent: 'center', 91 | alignItems: 'center' 92 | }, 93 | btnLogin: { 94 | backgroundColor: '#136E03' 95 | }, 96 | btnLoginText: { 97 | fontSize: 14, 98 | color: '#ffffff' 99 | }, 100 | btnSignup: { 101 | backgroundColor: '#ffffff' 102 | }, 103 | btnSignupText: { 104 | fontSize: 16, 105 | color: 'green' 106 | } 107 | }) 108 | -------------------------------------------------------------------------------- /Project13-AnimateTableViewCell/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | View, 3 | Text, 4 | Animated, 5 | Easing, 6 | ListView, 7 | StyleSheet 8 | } from 'react-native' 9 | 10 | import autobind from 'autobind-decorator' 11 | import LinearGradient from 'react-native-linear-gradient' 12 | import GoBack from '../GoBack' 13 | 14 | export const title = '13 - AnimateTableViewCell' 15 | export const description = '列表动画' 16 | 17 | const ds = new ListView.DataSource({ 18 | rowHasChanged: (r1, r2) => r1 !== r2 19 | }) 20 | 21 | const tableData = [ 22 | 'Read 3 article on Medium', 23 | 'Cleanup bedroom', 24 | 'Go for a run', 25 | 'Hit the gym', 26 | 'Build another swift project', 27 | 'Movement training', 28 | 'Fix the layout problem of a client project', 29 | 'Write the experience of #30daysSwift', 30 | 'Inbox Zero', 31 | 'Booking the ticket to Chengdu', 32 | 'Test the Adobe Project Comet', 33 | 'Hop on a call to mom' 34 | ] 35 | 36 | @autobind 37 | export default class AnimateTableViewCell extends React.Component { 38 | constructor () { 39 | super() 40 | this.state = { 41 | dataSource: ds.cloneWithRows(tableData), 42 | animTransiton: [], 43 | animOpacity: [] 44 | } 45 | } 46 | 47 | componentWillMount () { 48 | let animTransiton = [] 49 | let animOpacity = [] 50 | 51 | tableData.map((item, index) => { 52 | animTransiton[index] = new Animated.Value(250) 53 | animOpacity[index] = new Animated.Value(0) 54 | }) 55 | 56 | this.setState({animTransiton, animOpacity}) 57 | } 58 | 59 | componentDidMount () { 60 | this.state.animTransiton.map((item, index) => { 61 | Animated.timing(item, { 62 | toValue: 0, // 目标值 63 | duration: 900, // 动画时间 64 | delay: index * 100, 65 | easing: Easing.elastic(0.9) // 缓动函数 66 | }).start() 67 | }) 68 | 69 | this.state.animOpacity.map((item, index) => { 70 | Animated.timing(item, { 71 | toValue: 1, // 目标值 72 | duration: 900, // 动画时间 73 | delay: index * 100, 74 | easing: Easing.elastic(0.9) // 缓动函数 75 | }).start() 76 | }) 77 | } 78 | 79 | render () { 80 | return ( 81 | 82 | 86 | 87 | 88 | ) 89 | } 90 | 91 | _renderRow (rowData, sectionID, rowID) { 92 | const bgColor = this._getCellBgColor(rowID) 93 | const translateY = this.state.animTransiton[rowID] 94 | const opacity = this.state.animOpacity[rowID] 95 | 96 | return ( 97 | 98 | 99 | 111 | {rowData} 112 | 113 | 114 | 115 | ) 116 | } 117 | 118 | _getCellBgColor (index) { 119 | const totalCount = tableData.length - 1 120 | const color = Math.floor(256 * (Number(index) / totalCount) * 0.6) 121 | return `rgba(255, ${color}, 0, 1.0)` 122 | } 123 | } 124 | 125 | const styles = StyleSheet.create({ 126 | container: { 127 | flex: 1, 128 | backgroundColor: '#333333' 129 | }, 130 | linearGradient: { 131 | flex: 1, 132 | paddingLeft: 15, 133 | paddingRight: 15, 134 | justifyContent: 'center', 135 | alignItems: 'flex-start' 136 | }, 137 | tabelCell: { 138 | height: 60 139 | }, 140 | text: { 141 | color: '#ffffff', 142 | backgroundColor: 'transparent', 143 | fontFamily: 'Avenir Next', 144 | fontSize: 18 145 | } 146 | }) 147 | -------------------------------------------------------------------------------- /Project14-EmojiSlotMachine/images/Hyperspace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project14-EmojiSlotMachine/images/Hyperspace.jpg -------------------------------------------------------------------------------- /Project14-EmojiSlotMachine/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | Image, 6 | Picker, 7 | PickerIOS, 8 | Dimensions, 9 | TouchableHighlight 10 | } from 'react-native' 11 | 12 | import autobind from 'autobind-decorator' 13 | import GoBack from '../GoBack' 14 | const { width } = Dimensions.get('window') 15 | 16 | export const title = '14 - EmojiSlotMachine' 17 | export const description = 'Emoji抽奖机器' 18 | 19 | const imageArray = ['👻', '👸', '💩', '😘', '🍔', '🤖', '🍟', '🐼', '🚖', '🐷'] 20 | 21 | @autobind 22 | export default class EmojiSlotMachine extends React.Component { 23 | constructor (props) { 24 | super(props) 25 | 26 | this.state = { 27 | isSuccess: false 28 | } 29 | 30 | this.dataArray1 = [] 31 | this.dataArray2 = [] 32 | this.dataArray3 = [] 33 | } 34 | 35 | componentWillMount () { 36 | for (let i = 0; i < 100; i++) { 37 | this.dataArray1.push(Math.floor(Math.random() * 10)) 38 | this.dataArray2.push(Math.floor(Math.random() * 10)) 39 | this.dataArray3.push(Math.floor(Math.random() * 10)) 40 | } 41 | } 42 | 43 | render () { 44 | return ( 45 | 46 | 47 | this._onPickerChange(emoji, 'left')}> 51 | {this.dataArray1.map((item, index) => { 52 | const emoji = imageArray[item] 53 | return 54 | })} 55 | 56 | this._onPickerChange(emoji, 'middle')}> 60 | {this.dataArray2.map((item, index) => { 61 | const emoji = imageArray[item] 62 | return 63 | })} 64 | 65 | this._onPickerChange(emoji, 'right')}> 69 | {this.dataArray3.map((item, index) => { 70 | const emoji = imageArray[item] 71 | return 72 | })} 73 | 74 | 75 | 76 | this._go} underlayColor='transparent'> 77 | 78 | Go 79 | 80 | 81 | 82 | 83 | 84 | {this.state.isSuccess 85 | ? 'Bingo!' 86 | : '💔' 87 | } 88 | 89 | 90 | 91 | 92 | ) 93 | } 94 | 95 | _go () { 96 | 97 | } 98 | 99 | _onPickerChange (emoji, type) { 100 | 101 | } 102 | } 103 | 104 | const styles = StyleSheet.create({ 105 | container: { 106 | flex: 1, 107 | justifyContent: 'center' 108 | }, 109 | pickerContainer: { 110 | flex: 1, 111 | flexDirection: 'row', 112 | width, 113 | height: 80 114 | }, 115 | picker: { 116 | flex: 1, 117 | justifyContent: 'center' 118 | }, 119 | emoji: { 120 | fontSize: 60, 121 | lineHeight: 100 122 | }, 123 | buttonContainer: { 124 | position: 'absolute', 125 | bottom: 150, 126 | left: 0, 127 | width, 128 | justifyContent: 'center', 129 | alignItems: 'center' 130 | }, 131 | button: { 132 | width: 300, 133 | height: 40, 134 | borderRadius: 6, 135 | backgroundColor: 'yellow', 136 | justifyContent: 'center', 137 | alignItems: 'center' 138 | }, 139 | buttonText: { 140 | fontSize: 18, 141 | fontWeight: '800', 142 | color: 'green' 143 | }, 144 | result: { 145 | position: 'absolute', 146 | bottom: 60, 147 | left: 0, 148 | width, 149 | justifyContent: 'center', 150 | alignItems: 'center' 151 | }, 152 | resultText: { 153 | fontSize: 18, 154 | backgroundColor: 'transparent' 155 | } 156 | }) 157 | -------------------------------------------------------------------------------- /Project15-AnimatedSplash/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text 5 | } from 'react-native' 6 | 7 | import GoBack from '../GoBack' 8 | 9 | export const title = '15 - AnimatedSplash' 10 | export const description = '启动页' 11 | 12 | export default class AnimatedSplash extends React.Component { 13 | render () { 14 | return ( 15 | 16 | 目前需要原生支持 17 | 可以查看下面的项目看具体使用方式 18 | https://github.com/remobile/react-native-splashscreen 19 | 20 | 21 | ) 22 | } 23 | } 24 | 25 | const styles = StyleSheet.create({ 26 | container: { 27 | flex: 1, 28 | justifyContent: 'center', 29 | alignItems: 'center', 30 | backgroundColor: '#333333' 31 | }, 32 | text: { 33 | lineHeight: 30, 34 | color: '#ffffff' 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_IcesZKi5_400x400.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_IcesZKi5_400x400.jpeg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_LlCpvQc2_400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_LlCpvQc2_400x400.jpg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_MiDNqbJa_400x400.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_MiDNqbJa_400x400.jpeg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_catch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_catch.jpg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_photo-1449182325215-d517de72c42d.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_photo-1449182325215-d517de72c42d.jpeg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_weibo_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_weibo_square.png -------------------------------------------------------------------------------- /Project16-SlideMenu/images/avatar_xdBqvbba_400x400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/avatar_xdBqvbba_400x400.jpg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/haha_bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/haha_bg.jpeg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/live_free.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/live_free.png -------------------------------------------------------------------------------- /Project16-SlideMenu/images/lonely_traveler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/lonely_traveler.jpg -------------------------------------------------------------------------------- /Project16-SlideMenu/images/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/menu.png -------------------------------------------------------------------------------- /Project16-SlideMenu/images/menu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/menu@2x.png -------------------------------------------------------------------------------- /Project16-SlideMenu/images/menu@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/menu@3x.png -------------------------------------------------------------------------------- /Project16-SlideMenu/images/wallpaper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project16-SlideMenu/images/wallpaper.jpg -------------------------------------------------------------------------------- /Project16-SlideMenu/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | Navigator, 4 | ListView, 5 | View, 6 | Text, 7 | Image, 8 | Dimensions, 9 | TouchableOpacity 10 | } from 'react-native' 11 | 12 | import Animatable from 'react-native-animatable' 13 | import autobind from 'autobind-decorator' 14 | 15 | const { width } = Dimensions.get('window') 16 | 17 | const tableData = [ 18 | { 19 | avatar: require('./images/avatar_catch.jpg'), 20 | bg: require('./images/haha_bg.jpeg'), 21 | title: 'Love mountain.', 22 | author: 'Allen Wang' 23 | }, 24 | { 25 | avatar: require('./images/avatar_IcesZKi5_400x400.jpeg'), 26 | bg: require('./images/live_free.png'), 27 | title: 'New graphic design - LIVE FREE', 28 | author: 'Cole' 29 | }, 30 | { 31 | avatar: require('./images/avatar_LlCpvQc2_400x400.jpg'), 32 | bg: require('./images/lonely_traveler.jpg'), 33 | title: 'Summer sand', 34 | author: 'Daniel Hooper' 35 | }, 36 | { 37 | avatar: require('./images/avatar_MiDNqbJa_400x400.jpeg'), 38 | bg: require('./images/wallpaper.jpg'), 39 | title: 'Seeking for signal', 40 | author: 'Noby-Wan Kenobi' 41 | } 42 | ] 43 | const menuItems = [ 44 | 'Everyday Moments', 'Popular', 'Editors', 'Upcoming', 45 | 'Fresh', 'Stock-photos', 'Trending' 46 | ] 47 | const menuUpState = { 48 | height: 15, // 如果设置小于15,在收缩的时候会有抖动,不清楚原因 49 | opacity: 0, 50 | marginTop: -40 51 | } 52 | const menuDownState = { 53 | height: 400, 54 | opacity: 1, 55 | marginTop: 0 56 | } 57 | 58 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 59 | const NavigationBarRouteMapper = { 60 | LeftButton (route, navigator, index, navState) { 61 | return ( 62 | 65 | 66 | 返回 67 | 68 | 69 | ) 70 | }, 71 | 72 | Title (route, navigator, index, navState) { 73 | console.log(route.title) 74 | return ( 75 | 76 | {navigator.props.initialRoute.title} 77 | 78 | ) 79 | }, 80 | 81 | RightButton (route, navigator, index, navState) { 82 | return ( 83 | 86 | 87 | 🍔 88 | 89 | 90 | ) 91 | } 92 | } 93 | 94 | export const title = '16 - SlideMenu' 95 | export const description = '下拉菜单' 96 | 97 | @autobind 98 | export default class SlideMenu extends React.Component { 99 | constructor (props) { 100 | super(props) 101 | this.state = { 102 | currentTitle: menuItems[0], 103 | dataSource: ds.cloneWithRows(tableData.concat(...tableData)) 104 | } 105 | this.isMenuUp = true 106 | } 107 | 108 | render () { 109 | return ( 110 | 111 | 114 | {menuItems.map((item, index) => { 115 | return ( 116 | { 118 | this._onToggleSlideMenu(index) 119 | if (this.state.currentTitle !== item) { 120 | this.setState({currentTitle: item}) 121 | } 122 | }}> 123 | 124 | {item} 125 | 126 | 127 | ) 128 | })} 129 | 130 | ( 137 | 141 | )} 142 | navigationBar={ 143 | 151 | } 152 | /> 153 | 154 | ) 155 | } 156 | 157 | _renderRow (rowData, sectionID, rowID) { 158 | return ( 159 | 160 | 161 | 162 | {rowData.title} 163 | {rowData.author} 164 | 165 | 166 | ) 167 | } 168 | 169 | _onToggleSlideMenu () { 170 | if (this.isMenuUp) { 171 | this.refs.menuView.transitionTo(menuDownState) 172 | this.isMenuUp = false 173 | } else { 174 | this.refs.menuView.transitionTo(menuUpState) 175 | this.isMenuUp = true 176 | } 177 | } 178 | } 179 | 180 | const styles = StyleSheet.create({ 181 | container: { 182 | flex: 1, 183 | backgroundColor: '#333333' 184 | }, 185 | itemContainer: { 186 | flex: 1, 187 | position: 'relative', 188 | resizeMode: 'cover', 189 | width, // 一定加上width,不然image resizemode 会有问题 190 | height: 250, 191 | overflow: 'hidden' 192 | }, 193 | itemUser: { 194 | position: 'absolute', 195 | bottom: 20, 196 | left: 20, 197 | marginTop: 20 198 | }, 199 | itemAvatar: { 200 | width: 50, 201 | height: 50, 202 | overflow: 'hidden', 203 | borderRadius: 25 204 | }, 205 | itemTitle: { 206 | position: 'absolute', 207 | bottom: 24, 208 | left: 60, 209 | fontSize: 16, 210 | color: 'white' 211 | }, 212 | itemAuthor: { 213 | position: 'absolute', 214 | bottom: 4, 215 | left: 60, 216 | fontSize: 14, 217 | color: '#999999' 218 | }, 219 | navBar: { 220 | backgroundColor: 'rgba(0,0,0,0.9)' 221 | }, 222 | navBarText: { 223 | color: 'white', 224 | fontSize: 16, 225 | marginVertical: 10 226 | }, 227 | navBarTitleText: { 228 | fontWeight: '500', 229 | marginVertical: 9 230 | }, 231 | navBarLeftButton: { 232 | paddingLeft: 10 233 | }, 234 | navBarRightButton: { 235 | paddingRight: 10 236 | }, 237 | navBarButtonText: { 238 | fontSize: 14, 239 | color: '#eeeeee' 240 | }, 241 | scene: { 242 | flex: 1, 243 | paddingTop: 20, 244 | backgroundColor: '#EAEAEA' 245 | }, 246 | menuContainer: Object.assign({ 247 | backgroundColor: '#333333', 248 | paddingHorizontal: 15, 249 | paddingTop: 40 250 | }, menuUpState), 251 | itemMenuText: { 252 | fontSize: 20, 253 | fontFamily: 'Avenir Next', 254 | lineHeight: 36, 255 | color: '#666666' 256 | }, 257 | itemMenuDefaultText: { 258 | color: 'white' 259 | } 260 | }) 261 | -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/1-hjGpOnCIu4sP7H4V2sdFcA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/1-hjGpOnCIu4sP7H4V2sdFcA.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/22266727550_5decf72626_o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/22266727550_5decf72626_o.jpg -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/718835727.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/718835727.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/89w7SbqD_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/89w7SbqD_400x400.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Audio@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Audio@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Chat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Chat@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Link@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Link@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Photo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Photo@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Quote@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Quote@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/images/Text@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project17-TumblrMenu/images/Text@2x.png -------------------------------------------------------------------------------- /Project17-TumblrMenu/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | ListView, 4 | View, 5 | Text, 6 | Image, 7 | Dimensions, 8 | TouchableOpacity 9 | } from 'react-native' 10 | 11 | import autobind from 'autobind-decorator' 12 | import GoBack from '../GoBack' 13 | import { BlurView } from 'react-native-blur' 14 | import Animatable from 'react-native-animatable' 15 | import Icon from 'react-native-vector-icons/Ionicons' 16 | import Tabs from 'react-native-tabs' 17 | 18 | const {width, height} = Dimensions.get('window') 19 | const vw = width / 100 20 | const vh = height / 100 21 | 22 | const listData = [ 23 | {avatar: require('./images/718835727.png'), name: 'Hugo', pic: require('./images/1-hjGpOnCIu4sP7H4V2sdFcA.png')}, 24 | {avatar: require('./images/89w7SbqD_400x400.png'), name: 'MengTo', pic: require('./images/22266727550_5decf72626_o.jpg')} 25 | ] 26 | 27 | const menuData = [ 28 | { 29 | ref: 'text', text: 'Text', 30 | icon: require('./images/Text.png'), 31 | out: {left: -60, top: 80, opacity: 0}, 32 | in: {left: 50 * vw - 120, top: 80, opacity: 1} 33 | }, 34 | { 35 | ref: 'photo', text: 'Photo', 36 | icon: require('./images/Photo.png'), 37 | out: {right: -60, top: 80, opacity: 0}, 38 | in: {right: 50 * vw - 120, top: 80, opacity: 1} 39 | }, 40 | { 41 | ref: 'quote', text: 'Quote', 42 | icon: require('./images/Quote.png'), 43 | out: {left: -20, top: 240, opacity: 0}, 44 | in: {left: 50 * vw - 120, top: 240, opacity: 1} 45 | }, 46 | { 47 | ref: 'link', text: 'Link', 48 | icon: require('./images/Link.png'), 49 | out: {right: -20, top: 240, opacity: 0}, 50 | in: {right: 50 * vw - 120, top: 240, opacity: 1} 51 | }, 52 | { 53 | ref: 'chat', text: 'Chat', 54 | icon: require('./images/Chat.png'), 55 | out: {left: 20, top: 400, opacity: 0}, 56 | in: {left: 50 * vw - 120, top: 400, opacity: 1} 57 | }, 58 | { 59 | ref: 'audio', text: 'Audio', 60 | icon: require('./images/Audio.png'), 61 | out: {right: 20, top: 400, opacity: 0}, 62 | in: {right: 50 * vw - 120, top: 400, opacity: 1} 63 | } 64 | ] 65 | 66 | export const title = '17 - TumblrMenu' 67 | export const description = 'Tumblr菜单' 68 | 69 | @autobind 70 | export default class TumblrMenu extends React.Component { 71 | constructor () { 72 | super() 73 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 74 | this.state = { 75 | dataSource: ds.cloneWithRows(listData), 76 | isShow: false 77 | } 78 | } 79 | 80 | render () { 81 | return ( 82 | 83 | 89 | 90 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 104 | {menuData.map((item, index) => { 105 | return ( 106 | 107 | 108 | {item.text} 109 | 110 | ) 111 | })} 112 | 113 | Nevermind 114 | 115 | 116 | 117 | 118 | ) 119 | } 120 | 121 | _renderRow (rowData, sectionID, rowID) { 122 | return ( 123 | 124 | 125 | 126 | 127 | 128 | {rowData.name} 129 | 130 | 131 | 132 | ) 133 | } 134 | 135 | _toggleMenu () { 136 | if (this.state.isShow) { 137 | setTimeout(() => { 138 | this.setState({isShow: false}) 139 | }, 200) 140 | 141 | menuData.map(item => { 142 | this.refs[item.ref].transitionTo(item.out) 143 | }) 144 | } else { 145 | this.setState({isShow: true}) 146 | 147 | menuData.map(item => { 148 | this.refs[item.ref].transitionTo(item.in) 149 | }) 150 | } 151 | } 152 | } 153 | 154 | const styles = StyleSheet.create({ 155 | container: { 156 | flex: 1, 157 | backgroundColor: '#1F2C43' 158 | }, 159 | content: { 160 | marginTop: 60 161 | }, 162 | itemContainer: { 163 | marginTop: 20 164 | }, 165 | itemHeader: { 166 | flex: 1, 167 | flexDirection: 'row', 168 | width, 169 | backgroundColor: 'white', 170 | padding: 10 171 | }, 172 | itemAvatar: { 173 | width: 40, 174 | height: 40, 175 | marginRight: 10, 176 | borderRadius: 20 177 | }, 178 | itemName: { 179 | flex: 1, 180 | fontFamily: 'Avenir Next', 181 | lineHeight: 30, 182 | color: 'black' 183 | }, 184 | itemImage: { 185 | width, 186 | height: 250 187 | }, 188 | tab: { 189 | fontSize: 25, 190 | color: '#bbbbbb' 191 | }, 192 | tabEditContainer: { 193 | paddingVertical: 3, 194 | paddingHorizontal: 12, 195 | borderRadius: 5, 196 | backgroundColor: '#4F95C4' 197 | }, 198 | tabEdit: { 199 | color: '#333333' 200 | }, 201 | mark: { 202 | position: 'absolute', 203 | top: 0, 204 | left: 0, 205 | width, height, 206 | justifyContent: 'center' 207 | }, 208 | menuItem: { 209 | position: 'absolute', 210 | justifyContent: 'center', 211 | alignItems: 'center' 212 | }, 213 | menuText: { 214 | color: 'white' 215 | }, 216 | menuButton: { 217 | marginTop: 80 * vh, 218 | justifyContent: 'center', 219 | alignItems: 'center' 220 | }, 221 | menuButtonText: { 222 | fontSize: 18, 223 | fontWeight: '700', 224 | color: '#ffffff' 225 | } 226 | }) 227 | -------------------------------------------------------------------------------- /Project18-LimitCharacters/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/Project18-LimitCharacters/images/avatar.jpg -------------------------------------------------------------------------------- /Project18-LimitCharacters/index.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | StyleSheet, 3 | View, 4 | Text, 5 | Image, 6 | TextInput, 7 | Dimensions, 8 | ScrollView, 9 | TouchableOpacity 10 | } from 'react-native' 11 | 12 | import autobind from 'autobind-decorator' 13 | import GoBack from '../GoBack' 14 | import Icon from 'react-native-vector-icons/Ionicons' 15 | 16 | const {width, height} = Dimensions.get('window') 17 | const vw = width / 100 18 | const vh = height / 100 19 | 20 | export const title = '18 - LimitCharacters' 21 | export const description = '输入字数限制' 22 | 23 | @autobind 24 | export default class LimitCharacters extends React.Component { 25 | constructor () { 26 | super() 27 | this.state = { 28 | limitNum: 150 29 | } 30 | } 31 | 32 | render () { 33 | return ( 34 | 35 | 36 | 37 | 38 | 44 | 45 | 46 | {}}> 47 | Tweet 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {this.state.limitNum} 62 | 63 | 64 | 65 | ) 66 | } 67 | 68 | _onChange (text) { 69 | this.setState({limitNum: 150 - text.length}) 70 | } 71 | } 72 | 73 | const styles = StyleSheet.create({ 74 | container: { 75 | flex: 1, 76 | position: 'relative', 77 | backgroundColor: '#333333' 78 | }, 79 | tweet: { 80 | position: 'absolute', 81 | top: 40, 82 | right: 10 83 | }, 84 | tweetText: { 85 | fontSize: 18, 86 | fontWeight: '700', 87 | color: '#199634' 88 | }, 89 | content: { 90 | flex: 1, 91 | flexDirection: 'row', 92 | paddingTop: 80, 93 | paddingHorizontal: 20 94 | }, 95 | avatar: { 96 | width: 60, 97 | height: 60, 98 | borderRadius: 30, 99 | marginRight: 20 100 | }, 101 | textinput: { 102 | flex: 1, 103 | fontSize: 16, 104 | height: 600, 105 | overflow: 'hidden', 106 | color: 'white' 107 | }, 108 | actions: { 109 | flex: 1, 110 | flexDirection: 'row' 111 | }, 112 | limitNum: { 113 | color: '#ffffff', 114 | marginRight: 20 115 | }, 116 | footer: { 117 | flex: 1, 118 | flexDirection: 'row', 119 | height: 40, 120 | overflow: 'hidden' 121 | }, 122 | icon: { 123 | color: 'white', 124 | fontSize: 30, 125 | marginHorizontal: 10 126 | } 127 | }) 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/okoala/30DaysofReactNative/blob/master/screen.png) 2 | -------------------------------------------------------------------------------- /android/ThreetyDaysofReactNative.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"] 59 | * ] 60 | */ 61 | 62 | apply from: "react.gradle" 63 | 64 | /** 65 | * Set this to true to create two separate APKs instead of one: 66 | * - An APK that only works on ARM devices 67 | * - An APK that only works on x86 devices 68 | * The advantage is the size of the APK is reduced by about 4MB. 69 | * Upload all the APKs to the Play Store and people will download 70 | * the correct one based on the CPU architecture of their device. 71 | */ 72 | def enableSeparateBuildPerCPUArchitecture = false 73 | 74 | /** 75 | * Run Proguard to shrink the Java bytecode in release builds. 76 | */ 77 | def enableProguardInReleaseBuilds = false 78 | 79 | android { 80 | compileSdkVersion 23 81 | buildToolsVersion "23.0.1" 82 | 83 | defaultConfig { 84 | applicationId "com.threetydaysofreactnative" 85 | minSdkVersion 16 86 | targetSdkVersion 22 87 | versionCode 1 88 | versionName "1.0" 89 | ndk { 90 | abiFilters "armeabi-v7a", "x86" 91 | } 92 | } 93 | splits { 94 | abi { 95 | reset() 96 | enable enableSeparateBuildPerCPUArchitecture 97 | universalApk false // If true, also generate a universal APK 98 | include "armeabi-v7a", "x86" 99 | } 100 | } 101 | buildTypes { 102 | release { 103 | minifyEnabled enableProguardInReleaseBuilds 104 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 105 | } 106 | } 107 | // applicationVariants are e.g. debug, release 108 | applicationVariants.all { variant -> 109 | variant.outputs.each { output -> 110 | // For each separate APK per architecture, set a unique version code as described here: 111 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 112 | def versionCodes = ["armeabi-v7a":1, "x86":2] 113 | def abi = output.getFilter(OutputFile.ABI) 114 | if (abi != null) { // null for the universal-debug, universal-release variants 115 | output.versionCodeOverride = 116 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 117 | } 118 | } 119 | } 120 | } 121 | 122 | dependencies { 123 | compile project(':@remobile/react-native-splashscreen') 124 | compile project(':react-native-code-push') 125 | compile project(':react-native-sound') 126 | compile project(':react-native-linear-gradient') 127 | compile project(':react-native-camera') 128 | compile project(':react-native-video') 129 | compile project(':react-native-vector-icons') 130 | compile fileTree(dir: "libs", include: ["*.jar"]) 131 | compile "com.android.support:appcompat-v7:23.0.1" 132 | compile "com.facebook.react:react-native:+" // From node_modules 133 | } 134 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | 30 | # Do not strip any method/class that is annotated with @DoNotStrip 31 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 32 | -keepclassmembers class * { 33 | @com.facebook.proguard.annotations.DoNotStrip *; 34 | } 35 | 36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 37 | void set*(***); 38 | *** get*(); 39 | } 40 | 41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 43 | -keepclassmembers,includedescriptorclasses class * { native ; } 44 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 45 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 46 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 47 | 48 | -dontwarn com.facebook.react.** 49 | 50 | # okhttp 51 | 52 | -keepattributes Signature 53 | -keepattributes *Annotation* 54 | -keep class com.squareup.okhttp.** { *; } 55 | -keep interface com.squareup.okhttp.** { *; } 56 | -dontwarn com.squareup.okhttp.** 57 | 58 | # okio 59 | 60 | -keep class sun.misc.Unsafe { *; } 61 | -dontwarn java.nio.file.* 62 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 63 | -dontwarn okio.** 64 | 65 | # stetho 66 | 67 | -dontwarn com.facebook.stetho.** 68 | -------------------------------------------------------------------------------- /android/app/react.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | def config = project.hasProperty("react") ? project.react : []; 4 | 5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" 6 | def entryFile = config.entryFile ?: "index.android.js" 7 | 8 | // because elvis operator 9 | def elvisFile(thing) { 10 | return thing ? file(thing) : null; 11 | } 12 | 13 | def reactRoot = elvisFile(config.root) ?: file("../../") 14 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] 15 | 16 | void runBefore(String dependentTaskName, Task task) { 17 | Task dependentTask = tasks.findByPath(dependentTaskName); 18 | if (dependentTask != null) { 19 | dependentTask.dependsOn task 20 | } 21 | } 22 | 23 | gradle.projectsEvaluated { 24 | // Grab all build types and product flavors 25 | def buildTypes = android.buildTypes.collect { type -> type.name } 26 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name } 27 | 28 | // When no product flavors defined, use empty 29 | if (!productFlavors) productFlavors.add('') 30 | 31 | productFlavors.each { productFlavorName -> 32 | buildTypes.each { buildTypeName -> 33 | // Create variant and target names 34 | def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}" 35 | def targetPath = productFlavorName ? 36 | "${productFlavorName}/${buildTypeName}" : 37 | "${buildTypeName}" 38 | 39 | // React js bundle directories 40 | def jsBundleDirConfigName = "jsBundleDir${targetName}" 41 | def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: 42 | file("$buildDir/intermediates/assets/${targetPath}") 43 | 44 | def resourcesDirConfigName = "jsBundleDir${targetName}" 45 | def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: 46 | file("$buildDir/intermediates/res/merged/${targetPath}") 47 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName") 48 | 49 | // Bundle task name for variant 50 | def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets" 51 | 52 | def currentBundleTask = tasks.create( 53 | name: bundleJsAndAssetsTaskName, 54 | type: Exec) { 55 | group = "react" 56 | description = "bundle JS and assets for ${targetName}." 57 | 58 | // Create dirs if they are not there (e.g. the "clean" task just ran) 59 | doFirst { 60 | jsBundleDir.mkdirs() 61 | resourcesDir.mkdirs() 62 | } 63 | 64 | // Set up inputs and outputs so gradle can cache the result 65 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) 66 | outputs.dir jsBundleDir 67 | outputs.dir resourcesDir 68 | 69 | // Set up the call to the react-native cli 70 | workingDir reactRoot 71 | 72 | // Set up dev mode 73 | def devEnabled = !targetName.toLowerCase().contains("release") 74 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 75 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 76 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 77 | } else { 78 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 79 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 80 | } 81 | 82 | enabled config."bundleIn${targetName}" || 83 | config."bundleIn${buildTypeName.capitalize()}" ?: 84 | targetName.toLowerCase().contains("release") 85 | } 86 | 87 | // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process 88 | currentBundleTask.dependsOn("merge${targetName}Resources") 89 | currentBundleTask.dependsOn("merge${targetName}Assets") 90 | 91 | runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask) 92 | runBefore("processX86${targetName}Resources", currentBundleTask) 93 | runBefore("processUniversal${targetName}Resources", currentBundleTask) 94 | runBefore("process${targetName}Resources", currentBundleTask) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/com/threetydaysofreactnative/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.threetydaysofreactnative; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.remobile.splashscreen.RCTSplashScreenPackage; 5 | import com.microsoft.codepush.react.CodePushReactPackage; 6 | import com.zmxv.RNSound.RNSoundPackage; 7 | import com.BV.LinearGradient.LinearGradientPackage; 8 | import com.lwansbrough.RCTCamera.RCTCameraPackage; 9 | import com.brentvatne.RCTVideo.ReactVideoPackage; 10 | import com.oblador.vectoricons.VectorIconsPackage; 11 | import com.facebook.react.ReactPackage; 12 | import com.facebook.react.shell.MainReactPackage; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class MainActivity extends ReactActivity { 18 | 19 | /** 20 | * Returns the name of the main component registered from JavaScript. 21 | * This is used to schedule rendering of the component. 22 | */ 23 | @Override 24 | protected String getMainComponentName() { 25 | return "ThreetyDaysofReactNative"; 26 | } 27 | 28 | /** 29 | * Returns whether dev mode should be enabled. 30 | * This enables e.g. the dev menu. 31 | */ 32 | @Override 33 | protected boolean getUseDeveloperSupport() { 34 | return BuildConfig.DEBUG; 35 | } 36 | 37 | /** 38 | * A list of packages used by the app. If the app uses additional views 39 | * or modules besides the default ones, add more packages here. 40 | */ 41 | @Override 42 | protected List getPackages() { 43 | return Arrays.asList( 44 | new MainReactPackage(), 45 | new RCTSplashScreenPackage(), 46 | new CodePushReactPackage(), 47 | new RNSoundPackage(), 48 | new LinearGradientPackage(), 49 | new RCTCameraPackage(), 50 | new ReactVideoPackage(), 51 | new VectorIconsPackage() 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ThreetyDaysofReactNative 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | import groovy.json.JsonSlurper 3 | 4 | buildscript { 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:1.3.1' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | mavenLocal() 19 | jcenter() 20 | maven { 21 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 22 | url "$projectDir/../../node_modules/react-native/android" 23 | } 24 | } 25 | } 26 | 27 | subprojects { 28 | ext { 29 | def npmVersion = getNpmVersionArray() 30 | versionMajor = npmVersion[0] 31 | versionMinor = npmVersion[1] 32 | versionPatch = npmVersion[2] 33 | } 34 | } 35 | 36 | def getNpmVersion() { 37 | def inputFile = new File("../package.json") 38 | def packageJson = new JsonSlurper().parseText(inputFile.text) 39 | return packageJson["version"] 40 | } 41 | 42 | def getNpmVersionArray() { 43 | def (major, minor, patch) = getNpmVersion().tokenize('.') 44 | return [Integer.parseInt(major), Integer.parseInt(minor), Integer.parseInt(patch)] as int[] 45 | } 46 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ThreetyDaysofReactNative' 2 | 3 | include ':app' 4 | include ':react-native-vector-icons' 5 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 6 | include ':react-native-video' 7 | project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') 8 | include ':react-native-camera' 9 | project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') 10 | include ':react-native-linear-gradient' 11 | project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android') 12 | include ':react-native-sound' 13 | project(':react-native-sound').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sound/android') 14 | include ':react-native-code-push' 15 | project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app') 16 | include ':@remobile/react-native-splashscreen' 17 | project(':@remobile/react-native-splashscreen').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-splashscreen/android') 18 | -------------------------------------------------------------------------------- /checkUpdate.js: -------------------------------------------------------------------------------- 1 | import CodePush from 'react-native-code-push' 2 | import Loading from './Loading' 3 | 4 | export default function checkUpdate () { 5 | const options = { 6 | updateDialog: { 7 | appendReleaseDescription: true, 8 | title: '有更新', 9 | descriptionPrefix: '更新内容:', 10 | mandatoryContinueButtonLabel: '继续', 11 | mandatoryUpdateMessage: '必须更新才能继续使用', 12 | optionalIgnoreButtonLabel: '忽略', 13 | optionalInstallButtonLabel: '安装', 14 | optionalUpdateMessage: '有新的版本,你想要安装吗?' 15 | }, 16 | installMode: CodePush.InstallMode.IMMEDIATE 17 | } 18 | 19 | CodePush.sync(options, status => { 20 | switch (status) { 21 | case CodePush.SyncStatus.DOWNLOADING_PACKAGE: 22 | this.refs.nav.push({ 23 | component: Loading, 24 | title: ' ', 25 | navigationBarHidden: true, 26 | leftButtonTitle: '', 27 | onLeftButtonPress: () => {} 28 | }) 29 | break 30 | case CodePush.SyncStatus.INSTALLING_UPDATE: 31 | break 32 | case CodePush.SyncStatus.AWAITING_USER_ACTION: 33 | break 34 | } 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | */ 5 | 'use strict'; 6 | import React, { 7 | AppRegistry, 8 | Component, 9 | StyleSheet, 10 | Text, 11 | View 12 | } from 'react-native'; 13 | 14 | class ThreetyDaysofReactNative extends Component { 15 | render() { 16 | return ( 17 | 18 | 19 | Welcome to React Native! 20 | 21 | 22 | To get started, edit index.android.js 23 | 24 | 25 | Shake or press menu button for dev menu 26 | 27 | 28 | ); 29 | } 30 | } 31 | 32 | const styles = StyleSheet.create({ 33 | container: { 34 | flex: 1, 35 | justifyContent: 'center', 36 | alignItems: 'center', 37 | backgroundColor: '#F5FCFF', 38 | }, 39 | welcome: { 40 | fontSize: 20, 41 | textAlign: 'center', 42 | margin: 10, 43 | }, 44 | instructions: { 45 | textAlign: 'center', 46 | color: '#333333', 47 | marginBottom: 5, 48 | }, 49 | }); 50 | 51 | AppRegistry.registerComponent('ThreetyDaysofReactNative', () => ThreetyDaysofReactNative); 52 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | AppRegistry, 3 | StyleSheet, 4 | ScrollView, 5 | StatusBar, 6 | ListView, 7 | View, 8 | Text, 9 | Navigator, 10 | TouchableHighlight 11 | } from 'react-native' 12 | 13 | import autobind from 'autobind-decorator' 14 | import checkUpdate from './checkUpdate' 15 | import SplashScreen from '@remobile/react-native-splashscreen' 16 | 17 | const projects = [ 18 | require('./Project01-SimpleStopWatch'), 19 | require('./Project02-CustomFont'), 20 | require('./Project03-PlayLocalVideo'), 21 | require('./Project04-SnapChatMenu'), 22 | require('./Project05-CarouselEffect'), 23 | require('./Project06-FindMyLocation'), 24 | require('./Project07-PullToRefresh'), 25 | require('./Project08-RandomGradientColorMusic'), 26 | require('./Project09-ImageScroller'), 27 | require('./Project10-VideoBackground'), 28 | require('./Project11-ClearTableViewCell'), 29 | require('./Project12-LoginAnimation'), 30 | require('./Project13-AnimateTableViewCell'), 31 | require('./Project14-EmojiSlotMachine'), 32 | require('./Project15-AnimatedSplash'), 33 | require('./Project16-SlideMenu'), 34 | require('./Project17-TumblrMenu'), 35 | require('./Project18-LimitCharacters') 36 | ] 37 | 38 | class ThreetyDaysofReactNative extends React.Component { 39 | componentDidMount () { 40 | checkUpdate() 41 | SplashScreen.hide() 42 | } 43 | 44 | render () { 45 | return ( 46 | 47 | 50 | { 54 | return 55 | }} 56 | configureScene={(router, routeStack) => { 57 | if (router.SceneConfigs) { 58 | return router.SceneConfigs 59 | } 60 | return Navigator.SceneConfigs.PushFromRight 61 | }} 62 | /> 63 | 64 | ) 65 | } 66 | } 67 | 68 | @autobind 69 | class ProjectList extends React.Component { 70 | static propTypes = { 71 | navigator: React.PropTypes.object 72 | }; 73 | 74 | constructor () { 75 | super() 76 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 77 | this.state = { 78 | dataSource: ds.cloneWithRows(projects) 79 | } 80 | } 81 | 82 | render () { 83 | return ( 84 | 85 | 86 | 30DaysofReactNative 87 | 88 | 89 | 93 | 94 | 95 | ) 96 | } 97 | 98 | _renderRow (project, index) { 99 | return ( 100 | 101 | this._onPressRow(project)}> 102 | 103 | 104 | {project.title} 105 | 106 | 107 | {project.description} 108 | 109 | 110 | 111 | 112 | 113 | ) 114 | } 115 | 116 | _onPressRow (project) { 117 | this.props.navigator.push({ 118 | title: project.title, 119 | component: project.default 120 | }) 121 | } 122 | } 123 | 124 | const styles = StyleSheet.create({ 125 | container: { 126 | flex: 1 127 | }, 128 | content: { 129 | flex: 1 130 | }, 131 | list: { 132 | backgroundColor: '#eeeeee' 133 | }, 134 | titleBar: { 135 | height: 60, 136 | backgroundColor: '#05A5D1', 137 | justifyContent: 'center', 138 | alignItems: 'center' 139 | }, 140 | titleBarText: { 141 | fontSize: 18, 142 | fontWeight: '500', 143 | marginTop: 20, 144 | color: '#ffffff' 145 | }, 146 | row: { 147 | backgroundColor: 'white', 148 | justifyContent: 'center', 149 | paddingHorizontal: 15, 150 | paddingVertical: 8 151 | }, 152 | separator: { 153 | height: StyleSheet.hairlineWidth, 154 | backgroundColor: '#bbbbbb', 155 | marginLeft: 15 156 | }, 157 | rowTitleText: { 158 | color: '#ea4c89', 159 | fontSize: 17, 160 | fontWeight: '500' 161 | }, 162 | rowDetailText: { 163 | fontSize: 13, 164 | color: '#888888', 165 | lineHeight: 20, 166 | paddingLeft: 37 167 | } 168 | }) 169 | 170 | AppRegistry.registerComponent('ThreetyDaysofReactNative', () => ThreetyDaysofReactNative) 171 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative.xcodeproj/xcshareddata/xcschemes/ThreetyDaysofReactNative.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTRootView.h" 13 | #import "RCTSplashScreen.h" 14 | #import "CodePush.h" 15 | 16 | @implementation AppDelegate 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | NSURL *jsCodeLocation; 21 | 22 | /** 23 | * Loading JavaScript code - uncomment the one you want. 24 | * 25 | * OPTION 1 26 | * Load from development server. Start the server from the repository root: 27 | * 28 | * $ npm start 29 | * 30 | * To run on device, change `localhost` to the IP address of your computer 31 | * (you can get this by typing `ifconfig` into the terminal and selecting the 32 | * `inet` value under `en0:`) and make sure your computer and iOS device are 33 | * on the same Wi-Fi network. 34 | */ 35 | #ifdef DEBUG 36 | jsCodeLocation = [NSURL URLWithString:@"http://127.0.0.1:8081/index.ios.bundle?platform=ios&dev=true"]; 37 | #else 38 | jsCodeLocation = [CodePush bundleURL]; 39 | #endif 40 | /** 41 | * OPTION 2 42 | * Load from pre-bundled file on disk. The static bundle is automatically 43 | * generated by "Bundle React Native code and images" build step. 44 | */ 45 | 46 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 47 | 48 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 49 | moduleName:@"ThreetyDaysofReactNative" 50 | initialProperties:nil 51 | launchOptions:launchOptions]; 52 | [RCTSplashScreen show:rootView]; 53 | 54 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 55 | UIViewController *rootViewController = [UIViewController new]; 56 | rootViewController.view = rootView; 57 | self.window.rootViewController = rootViewController; 58 | [self.window makeKeyAndVisible]; 59 | return YES; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | NSLocationWhenInUseUsageDescription 31 | 32 | UIAppFonts 33 | 34 | MFZhiHei_Noncommercial-Regular.ttf 35 | MFTongXin_Noncommercial-Regular.ttf 36 | MFJinHei_Noncommercial-Regular.ttf 37 | Entypo.ttf 38 | EvilIcons.ttf 39 | FontAwesome.ttf 40 | Foundation.ttf 41 | Ionicons.ttf 42 | MaterialIcons.ttf 43 | Octicons.ttf 44 | Zocial.ttf 45 | 46 | UILaunchStoryboardName 47 | LaunchScreen 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UIViewControllerBasedStatusBarAppearance 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNative/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNativeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/ThreetyDaysofReactNativeTests/ThreetyDaysofReactNativeTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 240 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface ThreetyDaysofReactNativeTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation ThreetyDaysofReactNativeTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ThreetyDaysofReactNative", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "codepush": "react-native bundle", 8 | "fir": "fir build_ipa ./ios -o ./release -p -c 'this is changelog' -Q -T aa0252f3f9d84104465e525249ee729d", 9 | "preversion": "./scripts/version/pre.sh", 10 | "version": "./scripts/version/ios.sh", 11 | "postversion": "./scripts/version/post.sh" 12 | }, 13 | "dependencies": { 14 | "@remobile/react-native-splashscreen": "^1.0.3", 15 | "autobind-decorator": "^1.3.3", 16 | "react-native": "^0.22.0-rc", 17 | "react-native-animatable": "^0.5.1", 18 | "react-native-blur": "^0.7.10", 19 | "react-native-camera": "git+https://github.com/lwansbrough/react-native-camera.git", 20 | "react-native-code-push": "^1.7.3-beta", 21 | "react-native-linear-gradient": "^1.5.2", 22 | "react-native-sound": "^0.7.3", 23 | "react-native-swiper": "^1.4.3", 24 | "react-native-tabs": "^1.0.5", 25 | "react-native-vector-icons": "^1.2.1", 26 | "react-native-video": "^0.7.1", 27 | "react-native-viewport-units": "0.0.5" 28 | }, 29 | "devDependencies": { 30 | "babel": "6.5.2", 31 | "babel-core": "6.6.0", 32 | "babel-eslint": "^5.0.0", 33 | "babel-loader": "6.2.4", 34 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 35 | "babel-preset-react-native": "^1.4.0", 36 | "eslint": "^2.2.0", 37 | "eslint-config-standard": "^5.1.0", 38 | "eslint-plugin-promise": "^1.0.8", 39 | "eslint-plugin-react": "^4.1.0", 40 | "eslint-plugin-standard": "^1.3.2", 41 | "react": "^0.14.7", 42 | "webpack": "^2.1.0-beta.4" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okoala/30DaysofReactNative/0ff679ca9b9db1435eed3b967f6d9a0a98aef757/screen.png -------------------------------------------------------------------------------- /scripts/version/README.md: -------------------------------------------------------------------------------- 1 | ##### 项目的版本管理 2 | 3 | ![借鉴地址](https://github.com/AndrewJack/versioning-react-native-app) 4 | -------------------------------------------------------------------------------- /scripts/version/ios.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | PROJECT_DIR="ios/VersioningRN" 4 | INFOPLIST_FILE="Info.plist" 5 | INFOPLIST_DIR="${PROJECT_DIR}/${INFOPLIST_FILE}" 6 | 7 | PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') 8 | 9 | BUILD_NUMBER=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_DIR}") 10 | BUILD_NUMBER=$(($BUILD_NUMBER + 1)) 11 | 12 | 13 | # Update plist with new values 14 | /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${PACKAGE_VERSION#*v}" "${INFOPLIST_DIR}" 15 | /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "${INFOPLIST_DIR}" 16 | 17 | git add "${INFOPLIST_DIR}" 18 | -------------------------------------------------------------------------------- /scripts/version/post.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') 4 | 5 | git branch -m release/temp_$(git rev-parse --short HEAD^) release/$PACKAGE_VERSION 6 | 7 | # Push branch and tags 8 | git push origin release/$PACKAGE_VERSION 9 | git push origin --tags 10 | -------------------------------------------------------------------------------- /scripts/version/pre.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | git fetch --tags 4 | 5 | # create temp branch 6 | git checkout -b release/temp_$(git rev-parse --short HEAD) 7 | 8 | # Add changelog 9 | changelog 10 | git add CHANGELOG.md 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true 4 | }, 5 | "exclude": [ 6 | "node_modules" 7 | ] 8 | } --------------------------------------------------------------------------------