Re-design a loop model for avoid img flickering

This commit is contained in:
yuji
2015-05-01 17:30:48 +08:00
parent 3ade1c58ad
commit 9cb91c58c8
4 changed files with 269 additions and 163 deletions

View File

@@ -14,8 +14,6 @@ The best Swiper component for React Native.
- [ ] Check typo
- [ ] Optimal performance when `<Image />` re-render
- [x] Infinite loop
- [x] Direction control

139
dist/index.js vendored
View File

@@ -11,28 +11,18 @@ Object.defineProperty(exports, '__esModule', {
/*
react-native-swiper
feaure:
[x] loop
[x] dir
[x] custom style
[x] title
[x] multiple instances
[x] custom size
[x] control buttons
[x] autoplay
[ ] more switch effect
params(props):
- dir "x" || "y" @default: "x"
-dot Optionally provide the dot object show in pagination
@author leecade<leecade@163.com>
*/
var _React$StyleSheet$Text$View$ScrollView$TouchableOpacity = require('react-native');
var _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2 = _interopRequireWildcard(_React$StyleSheet$Text$View$ScrollView$TouchableOpacity);
// Using bare setTimeout, setInterval, setImmediate and requestAnimationFrame calls is very dangerous because if you forget to cancel the request before the component is unmounted, you risk the callback throwing an exception.
// Using bare setTimeout, setInterval, setImmediate
// and requestAnimationFrame calls is very dangerous
// because if you forget to cancel the request before
// the component is unmounted, you risk the callback
// throwing an exception.
var _TimerMixin = require('react-timer-mixin');
@@ -173,15 +163,27 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
*/
getInitialState: function getInitialState() {
var props = this.props;
var length = props.children ? props.children.length || 1 : 0;
return {
index: length > 1 ? props.index : 0,
total: length,
dir: props.horizontal == false ? 'y' : 'x',
width: props.width || width,
height: props.height || height,
var initState = {
isScrolling: false,
autoplayEnd: false };
initState.total = props.children ? props.children.length || 1 : 0;
initState.index = initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0;
// Default: horizontal
initState.dir = props.horizontal == false ? 'y' : 'x';
initState.width = props.width || width;
initState.height = props.height || height;
initState.offset = {};
if (initState.total > 1) {
var setup = props.loop ? 1 : initState.index;
initState.offset[initState.dir] = initState.dir == 'y' ? initState.height * setup : initState.width * setup;
}
return initState;
},
/**
@@ -190,14 +192,20 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
*/
autoplayTimer: null,
componentDidMount: function componentDidMount() {},
componentDidMount: function componentDidMount() {
this.autoplay();
},
/**
* Automatic rolling
*/
autoplay: function autoplay() {
var _this = this;
if (!this.props.autoplay || this.state.isScrolling || this.state.autoplayEnd) {
return;
}clearTimeout(this.autoplayTimer);
this.autoplayTimer = this.setTimeout(function () {
if (!_this.props.loop && (_this.props.autoplayDirection ? _this.state.index == _this.state.total - 1 : _this.state.index == 0)) return _this.setState({
autoplayEnd: true
@@ -206,22 +214,39 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
}, this.props.autoplayTimeout * 1000);
},
/**
* Scroll begin handle
* @param {object} e native event
*/
onScrollBegin: function onScrollBegin(e) {
// update scroll state
this.setState({
isScrolling: true
});
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag.call(this, e);
},
/**
* Scroll end handle
* @param {object} e native event
*/
onScrollEnd: function onScrollEnd(e) {
var _this2 = this;
// update scroll state
this.setState({
isScrolling: false
});
var offset = e.nativeEvent.contentOffset;
this.updateIndex(offset, this.state.dir);
this.updateIndex(e.nativeEvent.contentOffset, this.state.dir);
this.setTimeout(function () {
_this2.autoplay();
});
// if `onMomentumScrollEnd` registered will be called here
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this);
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this, e);
},
/**
@@ -230,17 +255,31 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
* @param {string} dir 'x' || 'y'
*/
updateIndex: function updateIndex(offset, dir) {
offset = offset[dir];
var state = this.state;
var index = state.index;
var diff = dir == 'x' ? state.width : state.height;
var diff = offset[dir] - state.offset[dir];
var step = dir == 'x' ? state.width : state.height;
// Do nothing if offset no change.
if (!diff) {
return;
} // Note: if touch very very quickly and continuous,
// the variation of `index` more than 1.
index = index + diff / step;
if (this.props.loop) {
if (offset > diff) index++;else if (offset < diff) index--;
if (index == -1) index = state.total - 1;else if (index == state.total) index = 0;
} else index = Math.floor((offset - diff / 2) / diff) + 1;
if (index <= -1) {
index = state.total - 1;
offset[dir] = step * state.total;
} else if (index >= state.total) {
index = 0;
offset[dir] = step;
}
}
this.setState({
index: index
});
index: index,
offset: offset });
},
/**
@@ -251,7 +290,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
if (this.state.isScrolling) {
return;
}var state = this.state;
var diff = (this.props.loop ? 1 : this.state.index) + index;
var diff = (this.props.loop ? 1 : 0) + index + this.state.index;
var x = 0;
var y = 0;
if (state.dir == 'x') x = diff * state.width;
@@ -312,7 +351,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
},
renderButtons: function renderButtons() {
var _this2 = this;
var _this3 = this;
var nextButton = this.props.nextButton || _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.Text,
@@ -332,7 +371,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.TouchableOpacity,
{ onPress: function () {
return !(!_this2.props.loop && _this2.state.index == 0) && _this2.scrollTo.call(_this2, -1);
return !(!_this3.props.loop && _this3.state.index == 0) && _this3.scrollTo.call(_this3, -1);
} },
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -343,7 +382,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.TouchableOpacity,
{ onPress: function () {
return !(!_this2.props.loop && _this2.state.index == _this2.state.total - 1) && _this2.scrollTo.call(_this2, 1);
return !(!_this3.props.loop && _this3.state.index == _this3.state.total - 1) && _this3.scrollTo.call(_this3, 1);
} },
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -366,7 +405,6 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
var total = state.total;
var loop = props.loop;
var dir = state.dir;
var initOffset = {};
var key = 0;
var pages = [];
@@ -374,12 +412,14 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
// For make infinite at least total > 1
if (total > 1) {
// Re-design a loop model for avoid img flickering
pages = Object.keys(children);
if (loop) {
pages.push(index == 0 ? total - 1 : index - 1);
pages.push(index);
pages.push(index == total - 1 ? 0 : index + 1);
key = index;
} else pages = Object.keys(children);
pages.unshift(total - 1);
pages.push(0);
}
pages = pages.map(function (page, i) {
return _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -387,17 +427,12 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
children[page]
);
});
var setup = loop ? 1 : index;
initOffset[dir] = dir == 'y' ? state.height * setup : state.width * setup;
} else pages = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
{ style: pageStyle },
children
);
this.autoplay();
return _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
{ style: [styles.container, {
@@ -409,9 +444,9 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
_extends({ ref: 'scrollView'
}, props, {
contentContainerStyle: [styles.wrapper, props.style],
contentOffset: initOffset,
onMomentumScrollEnd: this.onScrollEnd,
key: key }),
contentOffset: state.offset,
onScrollBeginDrag: this.onScrollBegin,
onMomentumScrollEnd: this.onScrollEnd }),
pages
),
props.showsPagination && (props.renderPagination ? this.props.renderPagination.call(this, state.index, state.total) : this.renderPagination()),

View File

@@ -11,28 +11,18 @@ Object.defineProperty(exports, '__esModule', {
/*
react-native-swiper
feaure:
[x] loop
[x] dir
[x] custom style
[x] title
[x] multiple instances
[x] custom size
[x] control buttons
[x] autoplay
[ ] more switch effect
params(props):
- dir "x" || "y" @default: "x"
-dot Optionally provide the dot object show in pagination
@author leecade<leecade@163.com>
*/
var _React$StyleSheet$Text$View$ScrollView$TouchableOpacity = require('react-native');
var _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2 = _interopRequireWildcard(_React$StyleSheet$Text$View$ScrollView$TouchableOpacity);
// Using bare setTimeout, setInterval, setImmediate and requestAnimationFrame calls is very dangerous because if you forget to cancel the request before the component is unmounted, you risk the callback throwing an exception.
// Using bare setTimeout, setInterval, setImmediate
// and requestAnimationFrame calls is very dangerous
// because if you forget to cancel the request before
// the component is unmounted, you risk the callback
// throwing an exception.
var _TimerMixin = require('react-timer-mixin');
@@ -139,7 +129,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
autoplayTimeout: _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].PropTypes.number,
autoplayDirection: _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].PropTypes.bool,
index: _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].PropTypes.number,
renderPagination: _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].PropTypes['function'] },
renderPagination: _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].PropTypes.func },
mixins: [_TimerMixin2['default']],
@@ -173,15 +163,27 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
*/
getInitialState: function getInitialState() {
var props = this.props;
var length = props.children ? props.children.length || 1 : 0;
return {
index: length > 1 ? props.index : 0,
total: length,
dir: props.horizontal == false ? 'y' : 'x',
width: props.width || width,
height: props.height || height,
var initState = {
isScrolling: false,
autoplayEnd: false };
initState.total = props.children ? props.children.length || 1 : 0;
initState.index = initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0;
// Default: horizontal
initState.dir = props.horizontal == false ? 'y' : 'x';
initState.width = props.width || width;
initState.height = props.height || height;
initState.offset = {};
if (initState.total > 1) {
var setup = props.loop ? 1 : initState.index;
initState.offset[initState.dir] = initState.dir == 'y' ? initState.height * setup : initState.width * setup;
}
return initState;
},
/**
@@ -190,14 +192,20 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
*/
autoplayTimer: null,
componentDidMount: function componentDidMount() {},
componentDidMount: function componentDidMount() {
this.autoplay();
},
/**
* Automatic rolling
*/
autoplay: function autoplay() {
var _this = this;
if (!this.props.autoplay || this.state.isScrolling || this.state.autoplayEnd) {
return;
}clearTimeout(this.autoplayTimer);
this.autoplayTimer = this.setTimeout(function () {
if (!_this.props.loop && (_this.props.autoplayDirection ? _this.state.index == _this.state.total - 1 : _this.state.index == 0)) return _this.setState({
autoplayEnd: true
@@ -206,22 +214,39 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
}, this.props.autoplayTimeout * 1000);
},
/**
* Scroll begin handle
* @param {object} e native event
*/
onScrollBegin: function onScrollBegin(e) {
// update scroll state
this.setState({
isScrolling: true
});
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag.call(this, e);
},
/**
* Scroll end handle
* @param {object} e native event
*/
onScrollEnd: function onScrollEnd(e) {
var _this2 = this;
// update scroll state
this.setState({
isScrolling: false
});
var offset = e.nativeEvent.contentOffset;
this.updateIndex(offset, this.state.dir);
this.updateIndex(e.nativeEvent.contentOffset, this.state.dir);
this.setTimeout(function () {
_this2.autoplay();
});
// if `onMomentumScrollEnd` registered will be called here
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this);
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this, e);
},
/**
@@ -230,17 +255,31 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
* @param {string} dir 'x' || 'y'
*/
updateIndex: function updateIndex(offset, dir) {
offset = offset[dir];
var state = this.state;
var index = state.index;
var diff = dir == 'x' ? state.width : state.height;
var diff = offset[dir] - state.offset[dir];
var step = dir == 'x' ? state.width : state.height;
// Do nothing if offset no change.
if (!diff) {
return;
} // Note: if touch very very quickly and continuous,
// the variation of `index` more than 1.
index = index + diff / step;
if (this.props.loop) {
if (offset > diff) index++;else if (offset < diff) index--;
if (index == -1) index = state.total - 1;else if (index == state.total) index = 0;
} else index = Math.floor((offset - diff / 2) / diff) + 1;
if (index <= -1) {
index = state.total - 1;
offset[dir] = step * state.total;
} else if (index >= state.total) {
index = 0;
offset[dir] = step;
}
}
this.setState({
index: index
});
index: index,
offset: offset });
},
/**
@@ -251,7 +290,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
if (this.state.isScrolling) {
return;
}var state = this.state;
var diff = (this.props.loop ? 1 : this.state.index) + index;
var diff = (this.props.loop ? 1 : 0) + index + this.state.index;
var x = 0;
var y = 0;
if (state.dir == 'x') x = diff * state.width;
@@ -312,7 +351,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
},
renderButtons: function renderButtons() {
var _this2 = this;
var _this3 = this;
var nextButton = this.props.nextButton || _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.Text,
@@ -332,7 +371,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.TouchableOpacity,
{ onPress: function () {
return !(!_this2.props.loop && _this2.state.index == 0) && _this2.scrollTo.call(_this2, -1);
return !(!_this3.props.loop && _this3.state.index == 0) && _this3.scrollTo.call(_this3, -1);
} },
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -343,7 +382,7 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.TouchableOpacity,
{ onPress: function () {
return !(!_this2.props.loop && _this2.state.index == _this2.state.total - 1) && _this2.scrollTo.call(_this2, 1);
return !(!_this3.props.loop && _this3.state.index == _this3.state.total - 1) && _this3.scrollTo.call(_this3, 1);
} },
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -366,7 +405,6 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
var total = state.total;
var loop = props.loop;
var dir = state.dir;
var initOffset = {};
var key = 0;
var pages = [];
@@ -374,12 +412,14 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
// For make infinite at least total > 1
if (total > 1) {
// Re-design a loop model for avoid img flickering
pages = Object.keys(children);
if (loop) {
pages.push(index == 0 ? total - 1 : index - 1);
pages.push(index);
pages.push(index == total - 1 ? 0 : index + 1);
key = index;
} else pages = Object.keys(children);
pages.unshift(total - 1);
pages.push(0);
}
pages = pages.map(function (page, i) {
return _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
@@ -387,17 +427,12 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
children[page]
);
});
var setup = loop ? 1 : index;
initOffset[dir] = dir == 'y' ? state.height * setup : state.width * setup;
} else pages = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
{ style: pageStyle },
children
);
this.autoplay();
return _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.View,
{ style: [styles.container, {
@@ -406,18 +441,18 @@ exports['default'] = _React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['d
}] },
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity2['default'].createElement(
_React$StyleSheet$Text$View$ScrollView$TouchableOpacity.ScrollView,
_extends({ ref: 'scrollView',
_extends({ ref: 'scrollView'
}, props, {
contentContainerStyle: [styles.wrapper, props.style],
contentOffset: initOffset,
key: key,
onMomentumScrollEnd: this.onScrollEnd
}, props),
contentOffset: state.offset,
onScrollBeginDrag: this.onScrollBegin,
onMomentumScrollEnd: this.onScrollEnd }),
pages
),
props.showsPagination && (props.renderPagination ? this.props.renderPagination(state.index, state.total) : this.renderPagination()),
props.showsPagination && (props.renderPagination ? this.props.renderPagination.call(this, state.index, state.total) : this.renderPagination()),
this.renderTitle(),
this.props.showsButtons && this.renderButtons()
);
}
});
module.exports = exports['default'];
module.exports = exports['default'];

View File

@@ -2,21 +2,7 @@
/*
react-native-swiper
feaure:
[x] loop
[x] dir
[x] custom style
[x] title
[x] multiple instances
[x] custom size
[x] control buttons
[x] autoplay
[ ] more switch effect
params(props):
- dir "x" || "y" @default: "x"
-dot Optionally provide the dot object show in pagination
@author leecade<leecade@163.com>
*/
import React, {
StyleSheet,
@@ -26,7 +12,11 @@ import React, {
TouchableOpacity,
} from 'react-native'
// Using bare setTimeout, setInterval, setImmediate and requestAnimationFrame calls is very dangerous because if you forget to cancel the request before the component is unmounted, you risk the callback throwing an exception.
// Using bare setTimeout, setInterval, setImmediate
// and requestAnimationFrame calls is very dangerous
// because if you forget to cancel the request before
// the component is unmounted, you risk the callback
// throwing an exception.
import TimerMixin from 'react-timer-mixin'
import Dimensions from 'Dimensions'
@@ -166,16 +156,34 @@ export default React.createClass({
*/
getInitialState() {
let props = this.props
let length = props.children ? (props.children.length || 1) : 0
return {
index: length > 1 ? props.index : 0,
total: length,
dir: props.horizontal == false ? 'y' : 'x',
width: props.width || width,
height: props.height || height,
let initState = {
isScrolling: false,
autoplayEnd: false,
}
initState.total = props.children
? (props.children.length || 1)
: 0
initState.index = initState.total > 1
? Math.min(props.index, initState.total - 1)
: 0
// Default: horizontal
initState.dir = props.horizontal == false ? 'y' : 'x'
initState.width = props.width || width
initState.height = props.height || height
initState.offset = {}
if(initState.total > 1) {
let setup = props.loop ? 1 : initState.index
initState.offset[initState.dir] = initState.dir == 'y'
? initState.height * setup
: initState.width * setup
}
return initState
},
/**
@@ -185,11 +193,19 @@ export default React.createClass({
autoplayTimer: null,
componentDidMount() {
this.autoplay()
},
/**
* Automatic rolling
*/
autoplay() {
if(!this.props.autoplay || this.state.isScrolling || this.state.autoplayEnd) return
if(!this.props.autoplay
|| this.state.isScrolling
|| this.state.autoplayEnd) return
clearTimeout(this.autoplayTimer)
this.autoplayTimer = this.setTimeout(() => {
if(!this.props.loop && (this.props.autoplayDirection
? this.state.index == this.state.total - 1
@@ -200,6 +216,19 @@ export default React.createClass({
}, this.props.autoplayTimeout * 1000)
},
/**
* Scroll begin handle
* @param {object} e native event
*/
onScrollBegin(e) {
// update scroll state
this.setState({
isScrolling: true
})
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag.call(this, e)
},
/**
* Scroll end handle
* @param {object} e native event
@@ -211,11 +240,14 @@ export default React.createClass({
isScrolling: false
})
let offset = e.nativeEvent.contentOffset
this.updateIndex(offset, this.state.dir)
this.updateIndex(e.nativeEvent.contentOffset, this.state.dir)
this.setTimeout(() => {
this.autoplay()
})
// if `onMomentumScrollEnd` registered will be called here
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this)
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd.call(this, e)
},
/**
@@ -224,19 +256,32 @@ export default React.createClass({
* @param {string} dir 'x' || 'y'
*/
updateIndex(offset, dir) {
offset = offset[dir]
let state = this.state
let index = state.index
let diff = dir == 'x' ? state.width : state.height
let diff = offset[dir] - state.offset[dir]
let step = dir == 'x' ? state.width : state.height
// Do nothing if offset no change.
if(!diff) return
// Note: if touch very very quickly and continuous,
// the variation of `index` more than 1.
index = index + diff / step
if(this.props.loop) {
if(offset > diff) index++
else if(offset < diff) index--
if(index == -1) index = state.total - 1
else if(index == state.total) index = 0
if(index <= -1) {
index = state.total - 1
offset[dir] = step * state.total
}
else if(index >= state.total) {
index = 0
offset[dir] = step
}
}
else index = Math.floor((offset - diff / 2) / diff) + 1
this.setState({
index: index
index: index,
offset: offset,
})
},
@@ -247,7 +292,7 @@ export default React.createClass({
scrollTo(index) {
if(this.state.isScrolling) return
let state = this.state
let diff = (this.props.loop ? 1 : this.state.index) + index
let diff = (this.props.loop ? 1 : 0) + index + this.state.index
let x = 0
let y = 0
if(state.dir == 'x') x = diff * state.width
@@ -349,7 +394,6 @@ export default React.createClass({
let total = state.total
let loop = props.loop
let dir = state.dir
let initOffset = {}
let key = 0
let pages = []
@@ -357,26 +401,20 @@ export default React.createClass({
// For make infinite at least total > 1
if(total > 1) {
// Re-design a loop model for avoid img flickering
pages = Object.keys(children)
if(loop) {
pages.push(index == 0 ? total - 1 : index - 1)
pages.push(index)
pages.push(index == total - 1 ? 0 : index + 1)
key = index
pages.unshift(total - 1)
pages.push(0)
}
else pages = Object.keys(children)
pages = pages.map((page, i) =>
<View style={pageStyle} key={i}>{children[page]}</View>
)
let setup = loop ? 1 : index
initOffset[dir] = dir == 'y'
? state.height * setup
: state.width * setup
}
else pages = <View style={pageStyle}>{children}</View>
this.autoplay()
return (
<View style={[styles.container, {
width: state.width,
@@ -385,9 +423,9 @@ export default React.createClass({
<ScrollView ref="scrollView"
{...props}
contentContainerStyle={[styles.wrapper, props.style]}
contentOffset={initOffset}
onMomentumScrollEnd={this.onScrollEnd}
key={key}>
contentOffset={state.offset}
onScrollBeginDrag={this.onScrollBegin}
onMomentumScrollEnd={this.onScrollEnd}>
{pages}
</ScrollView>
{props.showsPagination && (props.renderPagination