├── README.md
├── assets
└── dancingscript.ttf
├── demo.gif
├── exp.json
├── inspiration.gif
├── main.js
├── package.json
└── src
├── components
└── digital-magazine.js
├── img
├── page1.jpg
├── page2.jpg
├── page3.jpeg
└── page3.jpg
└── index.js
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-magazine-listview
2 | A pure javascript magazine listview for React Native framework.
3 |
4 | ###Inspiration
5 | 
6 |
7 | By Frederik Røssell from dribbble.com
8 | https://dribbble.com/shots/3058788-Digital-magazine-mockup
9 |
10 | ###Demo
11 | 
12 |
13 | ## Try it out
14 |
15 | Try it with Exponent: https://getexponent.com/@sungwoopark95/react-native-digital-magazine
16 |
17 | ## Run it locally
18 |
19 | To install, there are two steps:
20 |
21 | 1. Install Exponent XDE [following this
22 | guide](https://docs.getexponent.com/versions/latest/introduction/installation.html).
23 | Also install the Exponent app on your phone if you want to test it on
24 | your device, otherwise you don't need to do anything for the simulator.
25 | 2. Clone this repo and run `npm install`
26 | ```bash
27 | git clone https://github.com/ggomaeng/react-native-magazine-listview.git magazineListview
28 |
29 | cd magazineListview
30 | npm install
31 | ```
32 | 3. Open the project with Exponent XDE and run it.
33 |
--------------------------------------------------------------------------------
/assets/dancingscript.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/assets/dancingscript.ttf
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/demo.gif
--------------------------------------------------------------------------------
/exp.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-digital-magazine",
3 | "description": "An empty new project",
4 | "slug": "react-native-digital-magazine",
5 | "sdkVersion": "11.0.0",
6 | "version": "1.0.0",
7 | "orientation": "portrait",
8 | "primaryColor": "#cccccc",
9 | "iconUrl": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
10 | "notification": {
11 | "iconUrl": "https://s3.amazonaws.com/exp-us-standard/placeholder-push-icon-blue-circle.png",
12 | "color": "#000000"
13 | },
14 | "loading": {
15 | "iconUrl": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
16 | "hideExponentText": false
17 | },
18 | "packagerOpts": {
19 | "assetExts": ["ttf", "mp4"]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/inspiration.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/inspiration.gif
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import Exponent from 'exponent';
2 | import Main from './src/index';
3 |
4 | Exponent.registerRootComponent(Main);
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-digital-magazine",
3 | "version": "0.0.0",
4 | "description": "Hello Exponent!",
5 | "author": null,
6 | "private": true,
7 | "main": "main.js",
8 | "dependencies": {
9 | "exponent": "~11.0.2",
10 | "@exponent/vector-icons": "~2.0.3",
11 | "react": "~15.3.2",
12 | "react-native": "git+https://github.com/exponentjs/react-native#sdk-11.0.3"
13 | }
14 | }
--------------------------------------------------------------------------------
/src/components/digital-magazine.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by ggoma on 2016. 11. 25..
3 | */
4 | import Exponent from 'exponent';
5 | import React, {Component} from 'react';
6 | import {
7 | Animated,
8 | View,
9 | Text,
10 | Image,
11 | Dimensions,
12 | ListView,
13 | StyleSheet
14 | } from 'react-native';
15 |
16 | const {width, height} = Dimensions.get('window');
17 | const midpoint = width / 2;
18 |
19 | export default class DigitalMagazine extends Component {
20 | constructor(props) {
21 | super(props);
22 | const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
23 |
24 | this.state = {
25 | dataSource: ds.cloneWithRows(props.items),
26 | opacity: new Animated.Value(1),
27 |
28 | images: props.images.reverse(), //to stack the images in right order
29 | opacity_values : props.images.map(() => {
30 | return new Animated.Value(1)
31 | }),
32 | text_opacity : props.images.map(() => {
33 | return new Animated.Value(1)
34 | }),
35 | };
36 |
37 | this.page = props.images.length - 1; //backwards
38 | this.offset = 0;
39 | this._renderRow = this._renderRow.bind(this);
40 | this.handleScroll = this.handleScroll.bind(this);
41 |
42 | }
43 |
44 |
45 |
46 | _renderRow(row) {
47 | var {page, publisher, title, author, highlight, color} = row;
48 |
49 | return (
50 |
51 |
52 |
54 |
55 |
56 |
57 | {publisher}
58 |
59 |
60 |
61 |
62 |
63 | {highlight}{title}
64 |
65 |
66 |
67 |
68 |
69 | {author}
70 |
71 |
72 |
73 |
74 |
75 |
76 |
78 |
79 |
80 |
81 |
82 |
83 | )
84 | }
85 |
86 |
87 | handleScroll (event) {
88 | var e = event.nativeEvent;
89 |
90 | var currentOffset = e.contentOffset.x;
91 | var offset_ratio = (currentOffset / width);
92 | if(currentOffset > this.offset) {
93 | if(!Number.isInteger(offset_ratio) && offset_ratio > 0 ) {
94 | var page = Math.floor(offset_ratio);
95 | // console.log('scrolling right on page', page);
96 | var stack = Math.abs(page - this.state.opacity_values.length + 1);
97 | // console.log('position on stack', stack);
98 | //make current slide fade to 0
99 | if(stack != 0) { //check last page
100 | this.state.opacity_values[stack].setValue(Math.abs((currentOffset - ( width * (page +1) )) / width));
101 | //set current page to 0
102 | this.state.text_opacity[page].setValue(Math.abs((currentOffset - ( width * (page +1) )) / width));
103 | //set next page to 1 from 0
104 | this.state.text_opacity[page + 1].setValue(Math.abs((currentOffset - ( width * (page) )) / width));
105 | }
106 | }
107 | } else {
108 | if(!Number.isInteger(offset_ratio) && offset_ratio > 0) {
109 | var page = Math.ceil(offset_ratio);
110 | // console.log('scrolling left on page', page);
111 | var stack = Math.abs(page - this.state.opacity_values.length + 1);
112 | // console.log('position on stack', stack);
113 | if(this.state.opacity_values[stack + 1] != null && page < this.state.opacity_values.length) {
114 | //make previous slide fade to 1 -- remember, here uses math.ceil
115 | this.state.opacity_values[stack + 1].setValue(Math.abs(currentOffset - ( width * page )) / width);
116 | //set left page to 1
117 | this.state.text_opacity[page - 1].setValue(Math.abs((currentOffset - ( width * (page) )) / width));
118 | //set current page from 1 to 0
119 | this.state.text_opacity[page].setValue(Math.abs(currentOffset - (width * (page-1) )) / width);
120 |
121 | }
122 | }
123 | }
124 | this.offset = currentOffset;
125 |
126 | }
127 |
128 | renderImages() {
129 |
130 | var {images, opacity_values} = this.state;
131 |
132 | return images.map((image, i) => {
133 | return
134 | })
135 |
136 |
137 | }
138 |
139 |
140 | render() {
141 |
142 | var {images, page, opacity} = this.state;
143 | return (
144 |
145 | {this.renderImages()}
146 |
147 |
155 |
156 |
157 | )
158 | }
159 | }
160 |
161 | var styles = StyleSheet.create({
162 | img: {
163 | width: width,
164 | height: height,
165 | position: 'absolute',
166 | }
167 | })
--------------------------------------------------------------------------------
/src/img/page1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/src/img/page1.jpg
--------------------------------------------------------------------------------
/src/img/page2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/src/img/page2.jpg
--------------------------------------------------------------------------------
/src/img/page3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/src/img/page3.jpeg
--------------------------------------------------------------------------------
/src/img/page3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ggomaeng/react-native-magazine-listview/2ce20829950af757a37a5483c07a6b537486bda9/src/img/page3.jpg
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by ggoma on 2016. 11. 25..
3 | */
4 | import Exponent from 'exponent';
5 | import React from 'react';
6 | import {
7 | StyleSheet,
8 | Text,
9 | View,
10 | } from 'react-native';
11 |
12 | import DigitalMagazine from './components/digital-magazine';
13 |
14 | export default class App extends React.Component {
15 |
16 |
17 | state = {
18 | appIsReady: false,
19 | }
20 |
21 | async componentWillMount() {
22 | try {
23 | await Exponent.Font.loadAsync({cursive: require('../assets/dancingscript.ttf')});
24 | this.setState({appIsReady: true});
25 | } catch(e) {
26 | // console.warn(
27 | // 'There was an error caching assets (see: main.js), perhaps due to a ' +
28 | // 'network timeout, so we skipped caching. Reload the app to try again.'
29 | // );
30 | // console.log(e.message);
31 | }
32 | }
33 |
34 |
35 |
36 | render() {
37 | if (!this.state.appIsReady) {
38 | return (
39 |
40 | );
41 | }
42 |
43 | return (
44 |
45 |
59 |
60 | );
61 | }
62 | }
63 |
64 | const styles = StyleSheet.create({
65 | container: {
66 | flex: 1,
67 | backgroundColor: '#fff',
68 | },
69 | });
--------------------------------------------------------------------------------