@momo-kits/swipe 0.77.2 → 0.77.4
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/index.tsx +109 -0
- package/package.json +5 -5
- package/publish.sh +1 -1
- package/styles.ts +16 -0
- package/types.ts +23 -0
- package/SwipeAction.js +0 -708
- package/SwipeActionList.js +0 -162
- package/Swiper.js +0 -845
- package/index.js +0 -7
package/Swiper.js
DELETED
|
@@ -1,845 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/state-in-constructor */
|
|
2
|
-
/* eslint-disable react/static-property-placement */
|
|
3
|
-
/* eslint-disable no-multi-assign */
|
|
4
|
-
/* eslint-disable brace-style */
|
|
5
|
-
/* eslint-disable no-param-reassign */
|
|
6
|
-
/* eslint-disable react/no-array-index-key */
|
|
7
|
-
/* eslint-disable guard-for-in */
|
|
8
|
-
/* eslint-disable default-case */
|
|
9
|
-
/* eslint-disable react/destructuring-assignment */
|
|
10
|
-
/* eslint-disable no-restricted-syntax */
|
|
11
|
-
/**
|
|
12
|
-
* react-native-swiper
|
|
13
|
-
* @author leecade<leecade@163.com>
|
|
14
|
-
*/
|
|
15
|
-
import React, {Component} from 'react';
|
|
16
|
-
import PropTypes from 'prop-types';
|
|
17
|
-
import {
|
|
18
|
-
Text,
|
|
19
|
-
View,
|
|
20
|
-
ScrollView,
|
|
21
|
-
Dimensions,
|
|
22
|
-
TouchableOpacity,
|
|
23
|
-
Platform,
|
|
24
|
-
ActivityIndicator,
|
|
25
|
-
} from 'react-native';
|
|
26
|
-
import {ViewPager as ViewPagerAndroid} from '@momo-kits/core-v2';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Default styles
|
|
30
|
-
* @type {StyleSheetPropType}
|
|
31
|
-
*/
|
|
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
|
-
},
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
// missing `module.exports = exports['default'];` with babel6
|
|
108
|
-
// export default React.createClass({
|
|
109
|
-
export default class Swiper extends Component {
|
|
110
|
-
/**
|
|
111
|
-
* Props Validation
|
|
112
|
-
* @type {Object}
|
|
113
|
-
*/
|
|
114
|
-
static propTypes = {
|
|
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
|
-
/**
|
|
144
|
-
* Called when the index has changed because the user swiped.
|
|
145
|
-
*/
|
|
146
|
-
onIndexChanged: PropTypes.func,
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Default props
|
|
151
|
-
* @return {object} props
|
|
152
|
-
* @see http://facebook.github.io/react-native/docs/scrollview.html
|
|
153
|
-
*/
|
|
154
|
-
static defaultProps = {
|
|
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
|
-
};
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Init states
|
|
178
|
-
* @return {object} states
|
|
179
|
-
*/
|
|
180
|
-
state = this.initState(this.props);
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Initial render flag
|
|
184
|
-
* @type {bool}
|
|
185
|
-
*/
|
|
186
|
-
initialRender = true;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* autoplay timer
|
|
190
|
-
* @type {null}
|
|
191
|
-
*/
|
|
192
|
-
autoplayTimer = null;
|
|
193
|
-
|
|
194
|
-
loopJumpTimer = null;
|
|
195
|
-
|
|
196
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
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
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
componentDidMount() {
|
|
208
|
-
this.autoplay();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
componentWillUnmount() {
|
|
212
|
-
this.autoplayTimer && clearTimeout(this.autoplayTimer);
|
|
213
|
-
this.loopJumpTimer && clearTimeout(this.loopJumpTimer);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
UNSAFE_componentWillUpdate(nextProps, nextState) {
|
|
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
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
initState(props, updateIndex = false) {
|
|
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) {
|
|
243
|
-
// retain the index
|
|
244
|
-
initState.index = state.index;
|
|
245
|
-
} else {
|
|
246
|
-
initState.index =
|
|
247
|
-
initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Default: horizontal
|
|
251
|
-
const {width, height} = Dimensions.get('window');
|
|
252
|
-
|
|
253
|
-
initState.dir = props.horizontal === false ? 'y' : 'x';
|
|
254
|
-
|
|
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
|
-
}
|
|
262
|
-
|
|
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
|
-
}
|
|
270
|
-
|
|
271
|
-
initState.offset[initState.dir] =
|
|
272
|
-
initState.dir === 'y' ? height * props.index : width * props.index;
|
|
273
|
-
|
|
274
|
-
this.internals = {
|
|
275
|
-
...this.internals,
|
|
276
|
-
isScrolling: false,
|
|
277
|
-
};
|
|
278
|
-
return initState;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// include internals with state
|
|
282
|
-
fullState() {
|
|
283
|
-
return {...this.state, ...this.internals};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
onLayout = event => {
|
|
287
|
-
const {width, height} = event.nativeEvent.layout;
|
|
288
|
-
const offset = (this.internals.offset = {});
|
|
289
|
-
const state = {
|
|
290
|
-
width,
|
|
291
|
-
height,
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
if (this.state.total > 1) {
|
|
295
|
-
let setup = this.state.index;
|
|
296
|
-
if (this.props.loop) {
|
|
297
|
-
setup++;
|
|
298
|
-
}
|
|
299
|
-
offset[this.state.dir] =
|
|
300
|
-
this.state.dir === 'y' ? height * setup : width * setup;
|
|
301
|
-
}
|
|
302
|
-
|
|
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
|
-
}
|
|
312
|
-
|
|
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;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
this.setState(state);
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
loopJump = () => {
|
|
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
|
-
};
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Automatic rolling
|
|
343
|
-
*/
|
|
344
|
-
autoplay = () => {
|
|
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
|
-
};
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Scroll begin handle
|
|
371
|
-
* @param {object} e native event
|
|
372
|
-
*/
|
|
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
|
-
};
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Scroll end handle
|
|
382
|
-
* @param {object} e native event
|
|
383
|
-
*/
|
|
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
|
-
};
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
this.updateIndex(e.nativeEvent.contentOffset, this.state.dir, () => {
|
|
402
|
-
this.autoplay();
|
|
403
|
-
this.loopJump();
|
|
404
|
-
|
|
405
|
-
// if `onMomentumScrollEnd` registered will be called here
|
|
406
|
-
this.props.onMomentumScrollEnd &&
|
|
407
|
-
this.props.onMomentumScrollEnd(e, this.fullState(), this);
|
|
408
|
-
});
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/*
|
|
412
|
-
* Drag end handle
|
|
413
|
-
* @param {object} e native event
|
|
414
|
-
*/
|
|
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
|
-
};
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Update index after scroll
|
|
433
|
-
* @param {object} offset content offset
|
|
434
|
-
* @param {string} dir 'x' || 'y'
|
|
435
|
-
*/
|
|
436
|
-
updateIndex = (offset, dir, cb) => {
|
|
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;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const newState = {};
|
|
468
|
-
newState.index = index;
|
|
469
|
-
newState.loopJump = loopJump;
|
|
470
|
-
|
|
471
|
-
this.internals.offset = offset;
|
|
472
|
-
|
|
473
|
-
// only update offset in state if loopJump is true
|
|
474
|
-
if (loopJump) {
|
|
475
|
-
// when swiping to the beginning of a looping set for the third time,
|
|
476
|
-
// the new offset will be the same as the last one set in state.
|
|
477
|
-
// Setting the offset to the same thing will not do anything,
|
|
478
|
-
// so we increment it by 1 then immediately set it to what it should be,
|
|
479
|
-
// after render.
|
|
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
|
-
});
|
|
489
|
-
} else {
|
|
490
|
-
newState.offset = offset;
|
|
491
|
-
this.setState(newState, cb);
|
|
492
|
-
}
|
|
493
|
-
} else {
|
|
494
|
-
this.setState(newState, cb);
|
|
495
|
-
}
|
|
496
|
-
};
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Scroll by index
|
|
500
|
-
* @param {number} index offset index
|
|
501
|
-
* @param {bool} animated
|
|
502
|
-
*/
|
|
503
|
-
|
|
504
|
-
scrollBy = (index, animated = true) => {
|
|
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
|
-
}
|
|
524
|
-
|
|
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
|
-
});
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
scrollViewPropOverrides = () => {
|
|
544
|
-
const {props} = this;
|
|
545
|
-
const overrides = {};
|
|
546
|
-
|
|
547
|
-
/*
|
|
548
|
-
const scrollResponders = [
|
|
549
|
-
'onMomentumScrollBegin',
|
|
550
|
-
'onTouchStartCapture',
|
|
551
|
-
'onTouchStart',
|
|
552
|
-
'onTouchEnd',
|
|
553
|
-
'onResponderRelease',
|
|
554
|
-
]
|
|
555
|
-
*/
|
|
556
|
-
|
|
557
|
-
for (const prop in props) {
|
|
558
|
-
// if(~scrollResponders.indexOf(prop)
|
|
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);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
return overrides;
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
/**
|
|
574
|
-
* Render pagination
|
|
575
|
-
* @return {object} react-dom
|
|
576
|
-
*/
|
|
577
|
-
renderPagination = () => {
|
|
578
|
-
// By default, dots only show when `total` >= 2
|
|
579
|
-
if (this.state.total <= 1) return null;
|
|
580
|
-
|
|
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}),
|
|
621
|
-
);
|
|
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
|
-
};
|
|
635
|
-
|
|
636
|
-
renderTitle = () => {
|
|
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
|
-
};
|
|
646
|
-
|
|
647
|
-
renderNextButton = () => {
|
|
648
|
-
let button = null;
|
|
649
|
-
|
|
650
|
-
if (this.props.loop || this.state.index !== this.state.total - 1) {
|
|
651
|
-
button = this.props.nextButton || (
|
|
652
|
-
<Text style={styles.buttonText}>›</Text>
|
|
653
|
-
);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
return (
|
|
657
|
-
<TouchableOpacity
|
|
658
|
-
onPress={() => button !== null && this.scrollBy(1)}
|
|
659
|
-
disabled={this.props.disableNextButton}>
|
|
660
|
-
<View>{button}</View>
|
|
661
|
-
</TouchableOpacity>
|
|
662
|
-
);
|
|
663
|
-
};
|
|
664
|
-
|
|
665
|
-
renderPrevButton = () => {
|
|
666
|
-
let button = null;
|
|
667
|
-
|
|
668
|
-
if (this.props.loop || this.state.index !== 0) {
|
|
669
|
-
button = this.props.prevButton || (
|
|
670
|
-
<Text style={styles.buttonText}>‹</Text>
|
|
671
|
-
);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
return (
|
|
675
|
-
<TouchableOpacity onPress={() => button !== null && this.scrollBy(-1)}>
|
|
676
|
-
<View>{button}</View>
|
|
677
|
-
</TouchableOpacity>
|
|
678
|
-
);
|
|
679
|
-
};
|
|
680
|
-
|
|
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
|
-
};
|
|
700
|
-
|
|
701
|
-
onPageScrollStateChanged = state => {
|
|
702
|
-
switch (state) {
|
|
703
|
-
case 'dragging':
|
|
704
|
-
return this.onScrollBegin();
|
|
705
|
-
|
|
706
|
-
case 'idle':
|
|
707
|
-
case 'settling':
|
|
708
|
-
if (this.props.onTouchEnd) this.props.onTouchEnd();
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
renderScrollView = pages => {
|
|
713
|
-
if (Platform.OS === 'ios') {
|
|
714
|
-
return (
|
|
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>
|
|
727
|
-
);
|
|
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
|
-
};
|
|
742
|
-
|
|
743
|
-
checkPagesBeforeAfter = children => {
|
|
744
|
-
let str = '';
|
|
745
|
-
if (children && Array.isArray(children)) {
|
|
746
|
-
for (const child in children) {
|
|
747
|
-
str += children[child].key || child;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
return str;
|
|
751
|
-
};
|
|
752
|
-
|
|
753
|
-
/**
|
|
754
|
-
* Default render
|
|
755
|
-
* @return {object} react-dom
|
|
756
|
-
*/
|
|
757
|
-
render() {
|
|
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) {
|
|
792
|
-
// Re-design a loop model for avoid img flickering
|
|
793
|
-
pages = Object.keys(children);
|
|
794
|
-
// console.log(`checkPagesBeforeAfter children: ${JSON.stringify(this.checkPagesBeforeAfter(pages))}`);
|
|
795
|
-
|
|
796
|
-
if (loop) {
|
|
797
|
-
pages.unshift(`${total - 1}`);
|
|
798
|
-
pages.push('0');
|
|
799
|
-
}
|
|
800
|
-
|
|
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]}
|
|
822
|
-
</View>
|
|
823
|
-
);
|
|
824
|
-
});
|
|
825
|
-
} else {
|
|
826
|
-
pages = (
|
|
827
|
-
<View style={pageStyle} key={0}>
|
|
828
|
-
{children}
|
|
829
|
-
</View>
|
|
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
|
-
);
|
|
844
|
-
}
|
|
845
|
-
}
|