@momo-kits/swipe 0.0.74-beta → 0.72.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Swiper.js CHANGED
@@ -12,96 +12,96 @@
12
12
  * react-native-swiper
13
13
  * @author leecade<leecade@163.com>
14
14
  */
15
- import React, { Component } from 'react';
15
+ import React, {Component} from 'react';
16
16
  import PropTypes from 'prop-types';
17
17
  import {
18
- Text,
19
- View,
20
- ScrollView,
21
- Dimensions,
22
- TouchableOpacity,
23
- Platform,
24
- ActivityIndicator
18
+ Text,
19
+ View,
20
+ ScrollView,
21
+ Dimensions,
22
+ TouchableOpacity,
23
+ Platform,
24
+ ActivityIndicator,
25
25
  } from 'react-native';
26
- import { ViewPager as ViewPagerAndroid } from '@momo-kits/core';
26
+ import {ViewPager as ViewPagerAndroid} from '@momo-kits/core-v2';
27
27
 
28
28
  /**
29
29
  * Default styles
30
30
  * @type {StyleSheetPropType}
31
31
  */
32
32
  const styles = {
33
- container: {
34
- backgroundColor: 'transparent',
35
- position: 'relative',
36
- flex: 1
37
- },
38
-
39
- wrapperIOS: {
40
- backgroundColor: 'transparent',
41
- },
42
-
43
- wrapperAndroid: {
44
- backgroundColor: 'transparent',
45
- flex: 1
46
- },
47
-
48
- slide: {
49
- backgroundColor: 'transparent',
50
- },
51
-
52
- pagination_x: {
53
- position: 'absolute',
54
- bottom: 25,
55
- left: 0,
56
- right: 0,
57
- flexDirection: 'row',
58
- flex: 1,
59
- justifyContent: 'center',
60
- alignItems: 'center',
61
- backgroundColor: 'transparent'
62
- },
63
-
64
- pagination_y: {
65
- position: 'absolute',
66
- right: 15,
67
- top: 0,
68
- bottom: 0,
69
- flexDirection: 'column',
70
- flex: 1,
71
- justifyContent: 'center',
72
- alignItems: 'center',
73
- backgroundColor: 'transparent'
74
- },
75
-
76
- title: {
77
- height: 30,
78
- justifyContent: 'center',
79
- position: 'absolute',
80
- paddingLeft: 10,
81
- bottom: -30,
82
- left: 0,
83
- flexWrap: 'nowrap',
84
- width: 250,
85
- backgroundColor: 'transparent'
86
- },
87
-
88
- buttonWrapper: {
89
- backgroundColor: 'transparent',
90
- flexDirection: 'row',
91
- position: 'absolute',
92
- top: 0,
93
- left: 0,
94
- flex: 1,
95
- paddingHorizontal: 10,
96
- paddingVertical: 10,
97
- justifyContent: 'space-between',
98
- alignItems: 'center'
99
- },
100
-
101
- buttonText: {
102
- fontSize: 50,
103
- color: '#007aff'
104
- }
33
+ container: {
34
+ backgroundColor: 'transparent',
35
+ position: 'relative',
36
+ flex: 1,
37
+ },
38
+
39
+ wrapperIOS: {
40
+ backgroundColor: 'transparent',
41
+ },
42
+
43
+ wrapperAndroid: {
44
+ backgroundColor: 'transparent',
45
+ flex: 1,
46
+ },
47
+
48
+ slide: {
49
+ backgroundColor: 'transparent',
50
+ },
51
+
52
+ pagination_x: {
53
+ position: 'absolute',
54
+ bottom: 25,
55
+ left: 0,
56
+ right: 0,
57
+ flexDirection: 'row',
58
+ flex: 1,
59
+ justifyContent: 'center',
60
+ alignItems: 'center',
61
+ backgroundColor: 'transparent',
62
+ },
63
+
64
+ pagination_y: {
65
+ position: 'absolute',
66
+ right: 15,
67
+ top: 0,
68
+ bottom: 0,
69
+ flexDirection: 'column',
70
+ flex: 1,
71
+ justifyContent: 'center',
72
+ alignItems: 'center',
73
+ backgroundColor: 'transparent',
74
+ },
75
+
76
+ title: {
77
+ height: 30,
78
+ justifyContent: 'center',
79
+ position: 'absolute',
80
+ paddingLeft: 10,
81
+ bottom: -30,
82
+ left: 0,
83
+ flexWrap: 'nowrap',
84
+ width: 250,
85
+ backgroundColor: 'transparent',
86
+ },
87
+
88
+ buttonWrapper: {
89
+ backgroundColor: 'transparent',
90
+ flexDirection: 'row',
91
+ position: 'absolute',
92
+ top: 0,
93
+ left: 0,
94
+ flex: 1,
95
+ paddingHorizontal: 10,
96
+ paddingVertical: 10,
97
+ justifyContent: 'space-between',
98
+ alignItems: 'center',
99
+ },
100
+
101
+ buttonText: {
102
+ fontSize: 50,
103
+ color: '#007aff',
104
+ },
105
105
  };
106
106
 
107
107
  // missing `module.exports = exports['default'];` with babel6
@@ -112,48 +112,39 @@ export default class Swiper extends Component {
112
112
  * @type {Object}
113
113
  */
114
114
  static propTypes = {
115
- horizontal: PropTypes.bool,
116
- children: PropTypes.node.isRequired,
117
- containerStyle: PropTypes.oneOfType([
118
- PropTypes.object,
119
- PropTypes.number,
120
- ]),
121
- style: PropTypes.oneOfType([
122
- PropTypes.object,
123
- PropTypes.number,
124
- ]),
125
- scrollViewStyle: PropTypes.oneOfType([
126
- PropTypes.object,
127
- PropTypes.number,
128
- ]),
129
- pagingEnabled: PropTypes.bool,
130
- showsHorizontalScrollIndicator: PropTypes.bool,
131
- showsVerticalScrollIndicator: PropTypes.bool,
132
- bounces: PropTypes.bool,
133
- scrollsToTop: PropTypes.bool,
134
- removeClippedSubviews: PropTypes.bool,
135
- automaticallyAdjustContentInsets: PropTypes.bool,
136
- showsPagination: PropTypes.bool,
137
- showsButtons: PropTypes.bool,
138
- disableNextButton: PropTypes.bool,
139
- loadMinimal: PropTypes.bool,
140
- loadMinimalSize: PropTypes.number,
141
- loadMinimalLoader: PropTypes.element,
142
- loop: PropTypes.bool,
143
- autoplay: PropTypes.bool,
144
- autoplayTimeout: PropTypes.number,
145
- autoplayDirection: PropTypes.bool,
146
- index: PropTypes.number,
147
- renderPagination: PropTypes.func,
148
- dotStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
149
- activeDotStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
150
- dotColor: PropTypes.string,
151
- activeDotColor: PropTypes.string,
152
- /**
115
+ horizontal: PropTypes.bool,
116
+ children: PropTypes.node.isRequired,
117
+ containerStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
118
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
119
+ scrollViewStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
120
+ pagingEnabled: PropTypes.bool,
121
+ showsHorizontalScrollIndicator: PropTypes.bool,
122
+ showsVerticalScrollIndicator: PropTypes.bool,
123
+ bounces: PropTypes.bool,
124
+ scrollsToTop: PropTypes.bool,
125
+ removeClippedSubviews: PropTypes.bool,
126
+ automaticallyAdjustContentInsets: PropTypes.bool,
127
+ showsPagination: PropTypes.bool,
128
+ showsButtons: PropTypes.bool,
129
+ disableNextButton: PropTypes.bool,
130
+ loadMinimal: PropTypes.bool,
131
+ loadMinimalSize: PropTypes.number,
132
+ loadMinimalLoader: PropTypes.element,
133
+ loop: PropTypes.bool,
134
+ autoplay: PropTypes.bool,
135
+ autoplayTimeout: PropTypes.number,
136
+ autoplayDirection: PropTypes.bool,
137
+ index: PropTypes.number,
138
+ renderPagination: PropTypes.func,
139
+ dotStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
140
+ activeDotStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
141
+ dotColor: PropTypes.string,
142
+ activeDotColor: PropTypes.string,
143
+ /**
153
144
  * Called when the index has changed because the user swiped.
154
145
  */
155
- onIndexChanged: PropTypes.func
156
- }
146
+ onIndexChanged: PropTypes.func,
147
+ };
157
148
 
158
149
  /**
159
150
  * Default props
@@ -161,241 +152,281 @@ export default class Swiper extends Component {
161
152
  * @see http://facebook.github.io/react-native/docs/scrollview.html
162
153
  */
163
154
  static defaultProps = {
164
- horizontal: true,
165
- pagingEnabled: true,
166
- showsHorizontalScrollIndicator: false,
167
- showsVerticalScrollIndicator: false,
168
- bounces: false,
169
- scrollsToTop: false,
170
- removeClippedSubviews: true,
171
- automaticallyAdjustContentInsets: false,
172
- showsPagination: true,
173
- showsButtons: false,
174
- disableNextButton: false,
175
- loop: true,
176
- loadMinimal: false,
177
- loadMinimalSize: 1,
178
- autoplay: false,
179
- autoplayTimeout: 2.5,
180
- autoplayDirection: true,
181
- index: 0,
182
- onIndexChanged: () => null
183
- }
155
+ horizontal: true,
156
+ pagingEnabled: true,
157
+ showsHorizontalScrollIndicator: false,
158
+ showsVerticalScrollIndicator: false,
159
+ bounces: false,
160
+ scrollsToTop: false,
161
+ removeClippedSubviews: true,
162
+ automaticallyAdjustContentInsets: false,
163
+ showsPagination: true,
164
+ showsButtons: false,
165
+ disableNextButton: false,
166
+ loop: true,
167
+ loadMinimal: false,
168
+ loadMinimalSize: 1,
169
+ autoplay: false,
170
+ autoplayTimeout: 2.5,
171
+ autoplayDirection: true,
172
+ index: 0,
173
+ onIndexChanged: () => null,
174
+ };
184
175
 
185
176
  /**
186
177
  * Init states
187
178
  * @return {object} states
188
179
  */
189
- state = this.initState(this.props)
180
+ state = this.initState(this.props);
190
181
 
191
182
  /**
192
183
  * Initial render flag
193
184
  * @type {bool}
194
185
  */
195
- initialRender = true
186
+ initialRender = true;
196
187
 
197
188
  /**
198
189
  * autoplay timer
199
190
  * @type {null}
200
191
  */
201
- autoplayTimer = null
192
+ autoplayTimer = null;
202
193
 
203
- loopJumpTimer = null
194
+ loopJumpTimer = null;
204
195
 
205
196
  UNSAFE_componentWillReceiveProps(nextProps) {
206
- if (!nextProps.autoplay && this.autoplayTimer) clearTimeout(this.autoplayTimer);
207
- // Fix render last item first
208
- if (nextProps.index === this.props.index) return;
209
- this.setState(this.initState(nextProps, this.props.index !== nextProps.index));
197
+ if (!nextProps.autoplay && this.autoplayTimer) {
198
+ clearTimeout(this.autoplayTimer);
199
+ }
200
+ // Fix render last item first
201
+ if (nextProps.index === this.props.index) return;
202
+ this.setState(
203
+ this.initState(nextProps, this.props.index !== nextProps.index),
204
+ );
210
205
  }
211
206
 
212
207
  componentDidMount() {
213
- this.autoplay();
208
+ this.autoplay();
214
209
  }
215
210
 
216
211
  componentWillUnmount() {
217
- this.autoplayTimer && clearTimeout(this.autoplayTimer);
218
- this.loopJumpTimer && clearTimeout(this.loopJumpTimer);
212
+ this.autoplayTimer && clearTimeout(this.autoplayTimer);
213
+ this.loopJumpTimer && clearTimeout(this.loopJumpTimer);
219
214
  }
220
215
 
221
216
  UNSAFE_componentWillUpdate(nextProps, nextState) {
222
- // If the index has changed, we notify the parent via the onIndexChanged callback
223
- if (this.state.index !== nextState.index) this.props.onIndexChanged(nextState.index);
217
+ // If the index has changed, we notify the parent via the onIndexChanged callback
218
+ if (this.state.index !== nextState.index) {
219
+ this.props.onIndexChanged(nextState.index);
220
+ }
224
221
  }
225
222
 
226
223
  initState(props, updateIndex = false) {
227
- // set the current state
228
- const state = this.state || { width: 0, height: 0, offset: { x: 0, y: 0 } };
229
-
230
- const initState = {
231
- autoplayEnd: false,
232
- loopJump: false,
233
- offset: {}
234
- };
235
-
236
- initState.total = props.children ? props.children.length || 1 : 0;
237
-
238
- if (state.total === initState.total && !updateIndex) {
224
+ // set the current state
225
+ const state = this.state || {
226
+ width: 0,
227
+ height: 0,
228
+ offset: {
229
+ x: 0,
230
+ y: 0,
231
+ },
232
+ };
233
+
234
+ const initState = {
235
+ autoplayEnd: false,
236
+ loopJump: false,
237
+ offset: {},
238
+ };
239
+
240
+ initState.total = props.children ? props.children.length || 1 : 0;
241
+
242
+ if (state.total === initState.total && !updateIndex) {
239
243
  // retain the index
240
- initState.index = state.index;
241
- } else {
242
- initState.index = initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0;
243
- }
244
+ initState.index = state.index;
245
+ } else {
246
+ initState.index =
247
+ initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0;
248
+ }
244
249
 
245
- // Default: horizontal
246
- const { width, height } = Dimensions.get('window');
250
+ // Default: horizontal
251
+ const {width, height} = Dimensions.get('window');
247
252
 
248
- initState.dir = props.horizontal === false ? 'y' : 'x';
253
+ initState.dir = props.horizontal === false ? 'y' : 'x';
249
254
 
250
- if (props.width) {
251
- initState.width = props.width;
252
- } else if (this.state && this.state.width) {
253
- initState.width = this.state.width;
254
- } else {
255
- initState.width = width;
256
- }
255
+ if (props.width) {
256
+ initState.width = props.width;
257
+ } else if (this.state && this.state.width) {
258
+ initState.width = this.state.width;
259
+ } else {
260
+ initState.width = width;
261
+ }
257
262
 
258
- if (props.height) {
259
- initState.height = props.height;
260
- } else if (this.state && this.state.height) {
261
- initState.height = this.state.height;
262
- } else {
263
- initState.height = height;
264
- }
263
+ if (props.height) {
264
+ initState.height = props.height;
265
+ } else if (this.state && this.state.height) {
266
+ initState.height = this.state.height;
267
+ } else {
268
+ initState.height = height;
269
+ }
265
270
 
266
- initState.offset[initState.dir] = initState.dir === 'y'
267
- ? height * props.index
268
- : width * props.index;
271
+ initState.offset[initState.dir] =
272
+ initState.dir === 'y' ? height * props.index : width * props.index;
269
273
 
270
- this.internals = {
271
- ...this.internals,
272
- isScrolling: false
273
- };
274
- return initState;
274
+ this.internals = {
275
+ ...this.internals,
276
+ isScrolling: false,
277
+ };
278
+ return initState;
275
279
  }
276
280
 
277
281
  // include internals with state
278
282
  fullState() {
279
- return { ...this.state, ...this.internals };
283
+ return {...this.state, ...this.internals};
280
284
  }
281
285
 
282
- onLayout = (event) => {
283
- const { width, height } = event.nativeEvent.layout;
284
- const offset = this.internals.offset = {};
285
- const state = { width, height };
286
+ onLayout = event => {
287
+ const {width, height} = event.nativeEvent.layout;
288
+ const offset = (this.internals.offset = {});
289
+ const state = {
290
+ width,
291
+ height,
292
+ };
286
293
 
287
- if (this.state.total > 1) {
288
- let setup = this.state.index;
289
- if (this.props.loop) {
290
- setup++;
291
- }
292
- offset[this.state.dir] = this.state.dir === 'y'
293
- ? height * setup
294
- : width * setup;
294
+ if (this.state.total > 1) {
295
+ let setup = this.state.index;
296
+ if (this.props.loop) {
297
+ setup++;
295
298
  }
299
+ offset[this.state.dir] =
300
+ this.state.dir === 'y' ? height * setup : width * setup;
301
+ }
296
302
 
297
- // only update the offset in state if needed, updating offset while swiping
298
- // causes some bad jumping / stuttering
299
- if (!this.state.offset || width !== this.state.width || height !== this.state.height) {
300
- state.offset = offset;
301
- }
303
+ // only update the offset in state if needed, updating offset while swiping
304
+ // causes some bad jumping / stuttering
305
+ if (
306
+ !this.state.offset ||
307
+ width !== this.state.width ||
308
+ height !== this.state.height
309
+ ) {
310
+ state.offset = offset;
311
+ }
302
312
 
303
- // related to https://github.com/leecade/react-native-swiper/issues/570
304
- // contentOffset is not working in react 0.48.x so we need to use scrollTo
305
- // to emulate offset.
306
- if (Platform.OS === 'ios') {
307
- if (this.initialRender && this.state.total > 1) {
308
- this.scrollView.scrollTo({ ...offset, animated: false });
309
- this.initialRender = false;
310
- }
313
+ // related to https://github.com/leecade/react-native-swiper/issues/570
314
+ // contentOffset is not working in react 0.48.x so we need to use scrollTo
315
+ // to emulate offset.
316
+ if (Platform.OS === 'ios') {
317
+ if (this.initialRender && this.state.total > 1) {
318
+ this.scrollView.scrollTo({
319
+ ...offset,
320
+ animated: false,
321
+ });
322
+ this.initialRender = false;
311
323
  }
324
+ }
312
325
 
313
- this.setState(state);
314
- }
326
+ this.setState(state);
327
+ };
315
328
 
316
329
  loopJump = () => {
317
- if (!this.state.loopJump) return;
318
- const i = this.state.index + (this.props.loop ? 1 : 0);
319
- const { scrollView } = this;
320
- this.loopJumpTimer = setTimeout(() => scrollView.setPageWithoutAnimation
321
- && scrollView.setPageWithoutAnimation(i), 50);
322
- }
330
+ if (!this.state.loopJump) return;
331
+ const i = this.state.index + (this.props.loop ? 1 : 0);
332
+ const {scrollView} = this;
333
+ this.loopJumpTimer = setTimeout(
334
+ () =>
335
+ scrollView.setPageWithoutAnimation &&
336
+ scrollView.setPageWithoutAnimation(i),
337
+ 50,
338
+ );
339
+ };
323
340
 
324
341
  /**
325
342
  * Automatic rolling
326
343
  */
327
344
  autoplay = () => {
328
- if (!Array.isArray(this.props.children)
329
- || !this.props.autoplay
330
- || this.internals.isScrolling
331
- || this.state.autoplayEnd) return;
332
-
333
- this.autoplayTimer && clearTimeout(this.autoplayTimer);
334
- this.autoplayTimer = setTimeout(() => {
335
- if (!this.props.loop && (
336
- this.props.autoplayDirection
337
- ? this.state.index === this.state.total - 1
338
- : this.state.index === 0
339
- )
340
- ) return this.setState({ autoplayEnd: true });
341
-
342
- this.scrollBy(this.props.autoplayDirection ? 1 : -1);
343
- }, this.props.autoplayTimeout * 1000);
344
- }
345
+ if (
346
+ !Array.isArray(this?.props?.children) ||
347
+ !this.props.autoplay ||
348
+ this.internals.isScrolling ||
349
+ this.state.autoplayEnd
350
+ ) {
351
+ return;
352
+ }
353
+
354
+ this.autoplayTimer && clearTimeout(this.autoplayTimer);
355
+ this.autoplayTimer = setTimeout(() => {
356
+ if (
357
+ !this.props.loop &&
358
+ (this.props.autoplayDirection
359
+ ? this.state.index === this.state.total - 1
360
+ : this.state.index === 0)
361
+ ) {
362
+ return this.setState({autoplayEnd: true});
363
+ }
364
+
365
+ this.scrollBy(this.props.autoplayDirection ? 1 : -1);
366
+ }, this.props.autoplayTimeout * 1000);
367
+ };
345
368
 
346
369
  /**
347
370
  * Scroll begin handle
348
371
  * @param {object} e native event
349
372
  */
350
- onScrollBegin = (e) => {
351
- // update scroll state
352
- this.internals.isScrolling = true;
353
- this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e, this.fullState(), this);
354
- }
373
+ onScrollBegin = e => {
374
+ // update scroll state
375
+ this.internals.isScrolling = true;
376
+ this.props.onScrollBeginDrag &&
377
+ this.props.onScrollBeginDrag(e, this.fullState(), this);
378
+ };
355
379
 
356
380
  /**
357
381
  * Scroll end handle
358
382
  * @param {object} e native event
359
383
  */
360
- onScrollEnd = (e) => {
361
- // update scroll state
362
- this.internals.isScrolling = false;
363
-
364
- // making our events coming from android compatible to updateIndex logic
365
- if (!e.nativeEvent.contentOffset) {
366
- if (this.state.dir === 'x') {
367
- e.nativeEvent.contentOffset = { x: e.nativeEvent.position * this.state.width };
368
- } else {
369
- e.nativeEvent.contentOffset = { y: e.nativeEvent.position * this.state.height };
370
- }
384
+ onScrollEnd = e => {
385
+ // update scroll state
386
+ this.internals.isScrolling = false;
387
+
388
+ // making our events coming from android compatible to updateIndex logic
389
+ if (!e.nativeEvent.contentOffset) {
390
+ if (this.state.dir === 'x') {
391
+ e.nativeEvent.contentOffset = {
392
+ x: e.nativeEvent.position * this.state.width,
393
+ };
394
+ } else {
395
+ e.nativeEvent.contentOffset = {
396
+ y: e.nativeEvent.position * this.state.height,
397
+ };
371
398
  }
399
+ }
372
400
 
373
- this.updateIndex(e.nativeEvent.contentOffset, this.state.dir, () => {
374
- this.autoplay();
375
- this.loopJump();
401
+ this.updateIndex(e.nativeEvent.contentOffset, this.state.dir, () => {
402
+ this.autoplay();
403
+ this.loopJump();
376
404
 
377
- // if `onMomentumScrollEnd` registered will be called here
378
- this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e, this.fullState(), this);
379
- });
380
- }
405
+ // if `onMomentumScrollEnd` registered will be called here
406
+ this.props.onMomentumScrollEnd &&
407
+ this.props.onMomentumScrollEnd(e, this.fullState(), this);
408
+ });
409
+ };
381
410
 
382
411
  /*
383
412
  * Drag end handle
384
413
  * @param {object} e native event
385
414
  */
386
- onScrollEndDrag = (e) => {
387
- const { contentOffset } = e.nativeEvent;
388
- const { horizontal, children } = this.props;
389
- const { index } = this.state;
390
- const { offset } = this.internals;
391
- const previousOffset = horizontal ? offset.x : offset.y;
392
- const newOffset = horizontal ? contentOffset.x : contentOffset.y;
393
-
394
- if (previousOffset === newOffset
395
- && (index === 0 || index === children.length - 1)) {
396
- this.internals.isScrolling = false;
397
- }
398
- }
415
+ onScrollEndDrag = e => {
416
+ const {contentOffset} = e.nativeEvent;
417
+ const {horizontal, children} = this.props;
418
+ const {index} = this.state;
419
+ const {offset} = this.internals;
420
+ const previousOffset = horizontal ? offset.x : offset.y;
421
+ const newOffset = horizontal ? contentOffset.x : contentOffset.y;
422
+
423
+ if (
424
+ previousOffset === newOffset &&
425
+ (index === 0 || index === children.length - 1)
426
+ ) {
427
+ this.internals.isScrolling = false;
428
+ }
429
+ };
399
430
 
400
431
  /**
401
432
  * Update index after scroll
@@ -403,61 +434,66 @@ export default class Swiper extends Component {
403
434
  * @param {string} dir 'x' || 'y'
404
435
  */
405
436
  updateIndex = (offset, dir, cb) => {
406
- const { state } = this;
407
- let { index } = state;
408
- if (!this.internals.offset) // Android not setting this onLayout first? https://github.com/leecade/react-native-swiper/issues/582
409
- { this.internals.offset = {}; }
410
- const diff = offset[dir] - this.internals.offset[dir];
411
- const step = dir === 'x' ? state.width : state.height;
412
- let loopJump = false;
413
-
414
- // Do nothing if offset no change.
415
- if (!diff) return;
416
-
417
- // Note: if touch very very quickly and continuous,
418
- // the variation of `index` more than 1.
419
- // parseInt() ensures it's always an integer
420
- index = parseInt(index + Math.round(diff / step));
421
-
422
- if (this.props.loop) {
423
- if (index <= -1) {
424
- index = state.total - 1;
425
- offset[dir] = step * state.total;
426
- loopJump = true;
427
- } else if (index >= state.total) {
428
- index = 0;
429
- offset[dir] = step;
430
- loopJump = true;
431
- }
437
+ const {state} = this;
438
+ let {index} = state;
439
+ if (!this.internals.offset) {
440
+ // Android not setting this onLayout first? https://github.com/leecade/react-native-swiper/issues/582
441
+ this.internals.offset = {};
442
+ }
443
+ const diff = offset[dir] - this.internals.offset[dir];
444
+ const step = dir === 'x' ? state.width : state.height;
445
+ let loopJump = false;
446
+
447
+ // Do nothing if offset no change.
448
+ if (!diff) return;
449
+
450
+ // Note: if touch very very quickly and continuous,
451
+ // the variation of `index` more than 1.
452
+ // parseInt() ensures it's always an integer
453
+ index = parseInt(index + Math.round(diff / step));
454
+
455
+ if (this.props.loop) {
456
+ if (index <= -1) {
457
+ index = state.total - 1;
458
+ offset[dir] = step * state.total;
459
+ loopJump = true;
460
+ } else if (index >= state.total) {
461
+ index = 0;
462
+ offset[dir] = step;
463
+ loopJump = true;
432
464
  }
465
+ }
433
466
 
434
- const newState = {};
435
- newState.index = index;
436
- newState.loopJump = loopJump;
467
+ const newState = {};
468
+ newState.index = index;
469
+ newState.loopJump = loopJump;
437
470
 
438
- this.internals.offset = offset;
471
+ this.internals.offset = offset;
439
472
 
440
- // only update offset in state if loopJump is true
441
- if (loopJump) {
473
+ // only update offset in state if loopJump is true
474
+ if (loopJump) {
442
475
  // when swiping to the beginning of a looping set for the third time,
443
476
  // the new offset will be the same as the last one set in state.
444
477
  // Setting the offset to the same thing will not do anything,
445
478
  // so we increment it by 1 then immediately set it to what it should be,
446
479
  // after render.
447
- if (offset[dir] === this.internals.offset[dir]) {
448
- newState.offset = { x: 0, y: 0 };
449
- newState.offset[dir] = offset[dir] + 1;
450
- this.setState(newState, () => {
451
- this.setState({ offset }, cb);
452
- });
453
- } else {
454
- newState.offset = offset;
455
- this.setState(newState, cb);
456
- }
480
+ if (offset[dir] === this.internals.offset[dir]) {
481
+ newState.offset = {
482
+ x: 0,
483
+ y: 0,
484
+ };
485
+ newState.offset[dir] = offset[dir] + 1;
486
+ this.setState(newState, () => {
487
+ this.setState({offset}, cb);
488
+ });
457
489
  } else {
458
- this.setState(newState, cb);
490
+ newState.offset = offset;
491
+ this.setState(newState, cb);
459
492
  }
460
- }
493
+ } else {
494
+ this.setState(newState, cb);
495
+ }
496
+ };
461
497
 
462
498
  /**
463
499
  * Scroll by index
@@ -466,43 +502,49 @@ export default class Swiper extends Component {
466
502
  */
467
503
 
468
504
  scrollBy = (index, animated = true) => {
469
- if (this.internals.isScrolling || this.state.total < 2) return;
470
- const { state } = this;
471
- const diff = (this.props.loop ? 1 : 0) + index + this.state.index;
472
- let x = 0;
473
- let y = 0;
474
- if (state.dir === 'x') x = diff * state.width;
475
- if (state.dir === 'y') y = diff * state.height;
476
-
477
- if (Platform.OS !== 'ios') {
478
- this.scrollView && this.scrollView[animated ? 'setPage' : 'setPageWithoutAnimation'](diff);
479
- } else {
480
- this.scrollView && this.scrollView.scrollTo({ x, y, animated });
481
- }
505
+ if (this.internals.isScrolling || this.state.total < 2) return;
506
+ const {state} = this;
507
+ const diff = (this.props.loop ? 1 : 0) + index + this.state.index;
508
+ let x = 0;
509
+ let y = 0;
510
+ if (state.dir === 'x') x = diff * state.width;
511
+ if (state.dir === 'y') y = diff * state.height;
512
+
513
+ if (Platform.OS !== 'ios') {
514
+ this.scrollView &&
515
+ this.scrollView[animated ? 'setPage' : 'setPageWithoutAnimation'](diff);
516
+ } else {
517
+ this.scrollView &&
518
+ this.scrollView.scrollTo({
519
+ x,
520
+ y,
521
+ animated,
522
+ });
523
+ }
482
524
 
483
- // update scroll state
484
- this.internals.isScrolling = true;
485
- this.setState({
486
- autoplayEnd: false
525
+ // update scroll state
526
+ this.internals.isScrolling = true;
527
+ this.setState({
528
+ autoplayEnd: false,
529
+ });
530
+
531
+ // trigger onScrollEnd manually in android
532
+ if (!animated || Platform.OS !== 'ios') {
533
+ setImmediate(() => {
534
+ this.onScrollEnd({
535
+ nativeEvent: {
536
+ position: diff,
537
+ },
538
+ });
487
539
  });
488
-
489
- // trigger onScrollEnd manually in android
490
- if (!animated || Platform.OS !== 'ios') {
491
- setImmediate(() => {
492
- this.onScrollEnd({
493
- nativeEvent: {
494
- position: diff
495
- }
496
- });
497
- });
498
- }
499
- }
540
+ }
541
+ };
500
542
 
501
543
  scrollViewPropOverrides = () => {
502
- const { props } = this;
503
- const overrides = {};
544
+ const {props} = this;
545
+ const overrides = {};
504
546
 
505
- /*
547
+ /*
506
548
  const scrollResponders = [
507
549
  'onMomentumScrollBegin',
508
550
  'onTouchStartCapture',
@@ -512,187 +554,200 @@ export default class Swiper extends Component {
512
554
  ]
513
555
  */
514
556
 
515
- for (const prop in props) {
557
+ for (const prop in props) {
516
558
  // if(~scrollResponders.indexOf(prop)
517
- if (typeof props[prop] === 'function'
518
- && prop !== 'onMomentumScrollEnd'
519
- && prop !== 'renderPagination'
520
- && prop !== 'onScrollBeginDrag'
521
- ) {
522
- const originResponder = props[prop];
523
- overrides[prop] = (e) => originResponder(e, this.fullState(), this);
524
- }
559
+ if (
560
+ typeof props[prop] === 'function' &&
561
+ prop !== 'onMomentumScrollEnd' &&
562
+ prop !== 'renderPagination' &&
563
+ prop !== 'onScrollBeginDrag'
564
+ ) {
565
+ const originResponder = props[prop];
566
+ overrides[prop] = e => originResponder(e, this.fullState(), this);
525
567
  }
568
+ }
526
569
 
527
- return overrides;
528
- }
570
+ return overrides;
571
+ };
529
572
 
530
573
  /**
531
574
  * Render pagination
532
575
  * @return {object} react-dom
533
576
  */
534
577
  renderPagination = () => {
535
- // By default, dots only show when `total` >= 2
536
- if (this.state.total <= 1) return null;
537
-
538
- const dots = [];
539
- const ActiveDot = this.props.activeDot || (
540
- <View style={[{
541
- backgroundColor: this.props.activeDotColor || '#007aff',
542
- width: 8,
543
- height: 8,
544
- borderRadius: 4,
545
- marginLeft: 3,
546
- marginRight: 3,
547
- marginTop: 3,
548
- marginBottom: 3
549
- }, this.props.activeDotStyle]}
550
- />
551
- );
552
- const Dot = this.props.dot || (
553
- <View style={[{
554
- backgroundColor: this.props.dotColor || 'rgba(0,0,0,.2)',
555
- width: 8,
556
- height: 8,
557
- borderRadius: 4,
558
- marginLeft: 3,
559
- marginRight: 3,
560
- marginTop: 3,
561
- marginBottom: 3
562
- }, this.props.dotStyle]}
563
- />
564
- );
565
- for (let i = 0; i < this.state.total; i++) {
566
- dots.push(i === this.state.index
567
- ? React.cloneElement(ActiveDot, { key: i })
568
- : React.cloneElement(Dot, { key: i })
569
- );
570
- }
578
+ // By default, dots only show when `total` >= 2
579
+ if (this.state.total <= 1) return null;
571
580
 
572
- return (
573
- <View pointerEvents="none" style={[styles[`pagination_${this.state.dir}`], this.props.paginationStyle]}>
574
- {dots}
575
- </View>
581
+ const dots = [];
582
+ const ActiveDot = this.props.activeDot || (
583
+ <View
584
+ style={[
585
+ {
586
+ backgroundColor: this.props.activeDotColor || '#007aff',
587
+ width: 8,
588
+ height: 8,
589
+ borderRadius: 4,
590
+ marginLeft: 3,
591
+ marginRight: 3,
592
+ marginTop: 3,
593
+ marginBottom: 3,
594
+ },
595
+ this.props.activeDotStyle,
596
+ ]}
597
+ />
598
+ );
599
+ const Dot = this.props.dot || (
600
+ <View
601
+ style={[
602
+ {
603
+ backgroundColor: this.props.dotColor || 'rgba(0,0,0,.2)',
604
+ width: 8,
605
+ height: 8,
606
+ borderRadius: 4,
607
+ marginLeft: 3,
608
+ marginRight: 3,
609
+ marginTop: 3,
610
+ marginBottom: 3,
611
+ },
612
+ this.props.dotStyle,
613
+ ]}
614
+ />
615
+ );
616
+ for (let i = 0; i < this.state.total; i++) {
617
+ dots.push(
618
+ i === this.state.index
619
+ ? React.cloneElement(ActiveDot, {key: i})
620
+ : React.cloneElement(Dot, {key: i}),
576
621
  );
577
- }
622
+ }
623
+
624
+ return (
625
+ <View
626
+ pointerEvents="none"
627
+ style={[
628
+ styles[`pagination_${this.state.dir}`],
629
+ this.props.paginationStyle,
630
+ ]}>
631
+ {dots}
632
+ </View>
633
+ );
634
+ };
578
635
 
579
636
  renderTitle = () => {
580
- const child = this.props.children[this.state.index];
581
- const title = child && child.props && child.props.title;
582
- return title
583
- ? (
584
- <View style={styles.title}>
585
- {this.props.children[this.state.index].props.title}
586
- </View>
587
- )
588
- : null;
589
- }
637
+ let {children = []} = this.props;
638
+ const child = children[this.state.index];
639
+ const title = child && child.props && child.props.title;
640
+ return !!title ? (
641
+ <View style={styles.title}>
642
+ {this.props.children?.[this.state.index].props.title}
643
+ </View>
644
+ ) : null;
645
+ };
590
646
 
591
647
  renderNextButton = () => {
592
- let button = null;
648
+ let button = null;
593
649
 
594
- if (this.props.loop
595
- || this.state.index !== this.state.total - 1) {
596
- button = this.props.nextButton || <Text style={styles.buttonText}>›</Text>;
597
- }
598
-
599
- return (
600
- <TouchableOpacity
601
- onPress={() => button !== null && this.scrollBy(1)}
602
- disabled={this.props.disableNextButton}
603
- >
604
- <View>
605
- {button}
606
- </View>
607
- </TouchableOpacity>
650
+ if (this.props.loop || this.state.index !== this.state.total - 1) {
651
+ button = this.props.nextButton || (
652
+ <Text style={styles.buttonText}>›</Text>
608
653
  );
609
- }
654
+ }
610
655
 
611
- renderPrevButton = () => {
612
- let button = null;
656
+ return (
657
+ <TouchableOpacity
658
+ onPress={() => button !== null && this.scrollBy(1)}
659
+ disabled={this.props.disableNextButton}>
660
+ <View>{button}</View>
661
+ </TouchableOpacity>
662
+ );
663
+ };
613
664
 
614
- if (this.props.loop || this.state.index !== 0) {
615
- button = this.props.prevButton || <Text style={styles.buttonText}>‹</Text>;
616
- }
665
+ renderPrevButton = () => {
666
+ let button = null;
617
667
 
618
- return (
619
- <TouchableOpacity onPress={() => button !== null && this.scrollBy(-1)}>
620
- <View>
621
- {button}
622
- </View>
623
- </TouchableOpacity>
668
+ if (this.props.loop || this.state.index !== 0) {
669
+ button = this.props.prevButton || (
670
+ <Text style={styles.buttonText}>‹</Text>
624
671
  );
625
- }
672
+ }
626
673
 
627
- renderButtons = () => (
628
- <View
629
- pointerEvents="box-none"
630
- style={[styles.buttonWrapper, {
631
- width: this.state.width,
632
- height: this.state.height
633
- }, this.props.buttonWrapperStyle]}
634
- >
635
- {this.renderPrevButton()}
636
- {this.renderNextButton()}
637
- </View>
638
- )
674
+ return (
675
+ <TouchableOpacity onPress={() => button !== null && this.scrollBy(-1)}>
676
+ <View>{button}</View>
677
+ </TouchableOpacity>
678
+ );
679
+ };
639
680
 
640
- refScrollView = (view) => {
641
- this.scrollView = view;
642
- }
681
+ renderButtons = () => (
682
+ <View
683
+ pointerEvents="box-none"
684
+ style={[
685
+ styles.buttonWrapper,
686
+ {
687
+ width: this.state.width,
688
+ height: this.state.height,
689
+ },
690
+ this.props.buttonWrapperStyle,
691
+ ]}>
692
+ {this.renderPrevButton()}
693
+ {this.renderNextButton()}
694
+ </View>
695
+ );
696
+
697
+ refScrollView = view => {
698
+ this.scrollView = view;
699
+ };
643
700
 
644
- onPageScrollStateChanged = (state) => {
645
- switch (state) {
701
+ onPageScrollStateChanged = state => {
702
+ switch (state) {
646
703
  case 'dragging':
647
- return this.onScrollBegin();
704
+ return this.onScrollBegin();
648
705
 
649
706
  case 'idle':
650
707
  case 'settling':
651
- if (this.props.onTouchEnd) this.props.onTouchEnd();
652
- }
653
- }
708
+ if (this.props.onTouchEnd) this.props.onTouchEnd();
709
+ }
710
+ };
654
711
 
655
- renderScrollView = (pages) => {
656
- if (Platform.OS === 'ios') {
657
- return (
658
- <ScrollView
659
- ref={this.refScrollView}
660
- {...this.props}
661
- {...this.scrollViewPropOverrides()}
662
- contentContainerStyle={[styles.wrapperIOS, this.props.style]}
663
- contentOffset={this.state.offset}
664
- onScrollBeginDrag={this.onScrollBegin}
665
- onMomentumScrollEnd={this.onScrollEnd}
666
- onScrollEndDrag={this.onScrollEndDrag}
667
- style={this.props.scrollViewStyle}
668
- >
669
- {pages}
670
- </ScrollView>
671
- );
672
- }
712
+ renderScrollView = pages => {
713
+ if (Platform.OS === 'ios') {
673
714
  return (
674
- <ViewPagerAndroid
675
- ref={this.refScrollView}
676
- {...this.props}
677
- initialPage={this.props.loop ? this.state.index + 1 : this.state.index}
678
- onPageScrollStateChanged={this.onPageScrollStateChanged}
679
- onPageSelected={this.onScrollEnd}
680
- key={pages.length}
681
- style={[styles.wrapperAndroid, this.props.style]}
682
- >
683
- {pages}
684
- </ViewPagerAndroid>
715
+ <ScrollView
716
+ ref={this.refScrollView}
717
+ {...this.props}
718
+ {...this.scrollViewPropOverrides()}
719
+ contentContainerStyle={[styles.wrapperIOS, this.props.style]}
720
+ contentOffset={this.state.offset}
721
+ onScrollBeginDrag={this.onScrollBegin}
722
+ onMomentumScrollEnd={this.onScrollEnd}
723
+ onScrollEndDrag={this.onScrollEndDrag}
724
+ style={this.props.scrollViewStyle}>
725
+ {pages}
726
+ </ScrollView>
685
727
  );
686
- }
728
+ }
729
+ return (
730
+ <ViewPagerAndroid
731
+ ref={this.refScrollView}
732
+ {...this.props}
733
+ initialPage={this.props.loop ? this.state.index + 1 : this.state.index}
734
+ onPageScrollStateChanged={this.onPageScrollStateChanged}
735
+ onPageSelected={this.onScrollEnd}
736
+ key={pages.length}
737
+ style={[styles.wrapperAndroid, this.props.style]}>
738
+ {pages}
739
+ </ViewPagerAndroid>
740
+ );
741
+ };
687
742
 
688
- checkPagesBeforeAfter = (children) => {
689
- let str = '';
690
- if (children && Array.isArray(children)) {
691
- for (const child in children) {
692
- str += children[child].key || child;
693
- }
743
+ checkPagesBeforeAfter = children => {
744
+ let str = '';
745
+ if (children && Array.isArray(children)) {
746
+ for (const child in children) {
747
+ str += children[child].key || child;
694
748
  }
695
- return str;
749
+ }
750
+ return str;
696
751
  };
697
752
 
698
753
  /**
@@ -700,75 +755,91 @@ export default class Swiper extends Component {
700
755
  * @return {object} react-dom
701
756
  */
702
757
  render() {
703
- const {
704
- index,
705
- total,
706
- width,
707
- height
708
- } = this.state;
709
- const {
710
- children,
711
- containerStyle,
712
- loop,
713
- loadMinimal,
714
- loadMinimalSize,
715
- loadMinimalLoader,
716
- renderPagination,
717
- showsButtons,
718
- showsPagination,
719
- } = this.props;
720
- // let dir = state.dir
721
- // let key = 0
722
- const loopVal = loop ? 1 : 0;
723
- let pages = [];
724
-
725
- const pageStyle = [{ width, height }, styles.slide];
726
- const pageStyleLoading = {
727
- width,
728
- height,
729
- flex: 1,
730
- justifyContent: 'center',
731
- alignItems: 'center'
732
- };
733
-
734
- // For make infinite at least total > 1
735
- if (total > 1) {
758
+ const {index, total, width, height} = this.state;
759
+ const {
760
+ children,
761
+ containerStyle,
762
+ loop,
763
+ loadMinimal,
764
+ loadMinimalSize,
765
+ loadMinimalLoader,
766
+ renderPagination,
767
+ showsButtons,
768
+ showsPagination,
769
+ } = this.props;
770
+ // let dir = state.dir
771
+ // let key = 0
772
+ const loopVal = loop ? 1 : 0;
773
+ let pages = [];
774
+
775
+ const pageStyle = [
776
+ {
777
+ width,
778
+ height,
779
+ },
780
+ styles.slide,
781
+ ];
782
+ const pageStyleLoading = {
783
+ width,
784
+ height,
785
+ flex: 1,
786
+ justifyContent: 'center',
787
+ alignItems: 'center',
788
+ };
789
+
790
+ // For make infinite at least total > 1
791
+ if (total > 1) {
736
792
  // Re-design a loop model for avoid img flickering
737
- pages = Object.keys(children);
738
- // console.log(`checkPagesBeforeAfter children: ${JSON.stringify(this.checkPagesBeforeAfter(pages))}`);
793
+ pages = Object.keys(children);
794
+ // console.log(`checkPagesBeforeAfter children: ${JSON.stringify(this.checkPagesBeforeAfter(pages))}`);
739
795
 
740
- if (loop) {
741
- pages.unshift(`${total - 1}`);
742
- pages.push('0');
743
- }
744
-
745
- pages = pages.map((page, i) => {
746
- if (loadMinimal) {
747
- if (i >= (index + loopVal - loadMinimalSize)
748
- && i <= (index + loopVal + loadMinimalSize)) {
749
- return <View style={pageStyle} key={i}>{children[page]}</View>;
750
- }
751
- return (
752
- <View style={pageStyleLoading} key={i}>
753
- {loadMinimalLoader || <ActivityIndicator />}
754
- </View>
755
- );
756
- }
757
- return <View style={pageStyle} key={i}>{children[page]}</View>;
758
- });
759
- } else {
760
- pages = <View style={pageStyle} key={0}>{children}</View>;
796
+ if (loop) {
797
+ pages.unshift(`${total - 1}`);
798
+ pages.push('0');
761
799
  }
762
800
 
763
- return (
764
- <View style={[styles.container, containerStyle]} onLayout={this.onLayout}>
765
- {this.renderScrollView(pages)}
766
- {showsPagination && (renderPagination
767
- ? renderPagination(index, total, this)
768
- : this.renderPagination())}
769
- {this.renderTitle()}
770
- {showsButtons && this.renderButtons()}
801
+ pages = pages.map((page, i) => {
802
+ if (loadMinimal) {
803
+ if (
804
+ i >= index + loopVal - loadMinimalSize &&
805
+ i <= index + loopVal + loadMinimalSize
806
+ ) {
807
+ return (
808
+ <View style={pageStyle} key={i}>
809
+ {children[page]}
810
+ </View>
811
+ );
812
+ }
813
+ return (
814
+ <View style={pageStyleLoading} key={i}>
815
+ {loadMinimalLoader || <ActivityIndicator />}
816
+ </View>
817
+ );
818
+ }
819
+ return (
820
+ <View style={pageStyle} key={i}>
821
+ {children[page]}
771
822
  </View>
823
+ );
824
+ });
825
+ } else {
826
+ pages = (
827
+ <View style={pageStyle} key={0}>
828
+ {children}
829
+ </View>
772
830
  );
831
+ }
832
+
833
+ return (
834
+ <View style={[styles.container, containerStyle]} onLayout={this.onLayout}>
835
+ {this.renderScrollView(pages)}
836
+ {showsPagination &&
837
+ (renderPagination
838
+ ? renderPagination(index, total, this)
839
+ : this.renderPagination())}
840
+ {this.renderTitle()}
841
+ {showsButtons && this.renderButtons()}
842
+ </View>
843
+ );
773
844
  }
774
845
  }