Skip to content

Commit

Permalink
Merge pull request #1 from Exilz/evolution
Browse files Browse the repository at this point in the history
Evolution
  • Loading branch information
bd-arc authored Oct 10, 2016
2 parents 6bee158 + 8598240 commit 2eb3b44
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 21 deletions.
38 changes: 32 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Simple carousel component with snapping effect on Android & iOS for React Native
$ npm install --save react-native-snap-carousel
```

```
```javascript
import Carousel from 'react-native-snap-carousel';

_renderItem (data, index) {
Expand All @@ -26,7 +26,6 @@ import Carousel from 'react-native-snap-carousel';
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
itemHorizontalMargin={itemHorizontalMargin}
slideStyle={styles.slide} />
}
```
Expand All @@ -40,7 +39,6 @@ Prop | Description | Type | Default
items | Array of items to loop on | Array | Required
sliderWidth | The width in pixels of your slider | Number | Required
itemWidth | Width in pixels of your items | Number | Required
itemHorizontalMargin | Width in pixels of the horizontal margin between your elements | Number | Required
renderItem | Function returning a react element. The entry data is the 1st parameter, its index is the 2nd | Function | Required
slideStyle | Style of each item's container | Number | Required
swipeThreshold | Delta x when swiping to trigger the snap | Number | `20`
Expand All @@ -49,21 +47,49 @@ animationOptions | Animation options to be merged with the default ones. Can be
firstItem | Index of the first item to display | Number | `0`
autoplay | Trigger autoplay on mount | Boolean | `false`
autoplayInterval | Delay in ms until navigating to the next item | `3000`
autoplayDelay | Deay before enabling autoplay on startup & after releasing the touch | Number | `5000`
autoplayDelay | Delay before enabling autoplay on startup & after releasing the touch | Number | `5000`
enableSnap | If enabled, releasing the touch will scroll to the center of the nearest/active item | Number | `true`
snapOnAndroid | Snapping on android is kinda choppy, especially when swiping quickly so you can disable it | Boolean | `false`
containerCustomStyle | Optional styles for Scrollview's global wrapper | Number | `null`
contentContainerCustomStyle | Optional styles for Scrollview's items container | Number | `null`
inactiveSlideScale | Value of the 'scale' transform applied to inactive slides | Number | `0.9`
inactiveSlideOpacity | Value of the opacity effect applied to inactive slides | Number | `1`

## Methods

* `startAutoplay (instantly = false)` Start the autoplay manually
* `stopAutoplay ()` Stop the autoplay manually
* `snapToItem (index, animated = true)` Snap to an item manually

## Tips and tricks

### Margin between slides
If you need some **extra horizontal margin** between slides (besides the one resulting from the scale effect), you should add it as `paddingHorizontal` on the slide container. Make sure to take this into account when calculating item's width.

```javascript
const slideWidth = 250;
const horizontalMargin = 40;
const itemWidth = slideWidth + horizontalMargin * 2;

const styles = Stylesheet.create({
slide: {
width: itemWidth
// other styles for your item's container
}
};

<Carousel
itemWidth={itemWidth}
slideStyle={styles.slide}
/>

```
## TODO :
- [ ] Improve snap on Android
- [ ] Fix centering since it's a little off
- [ ] Handle passing 1 item only
- [ ] Handle changing props on-the-fly
- [ ] Handle device orientation event
- [ ] Add Vertical implementation
- [x] Fix centering since it's a little off
- [x] Handle passing 1 item only
63 changes: 48 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ export default class Carousel extends Component {
* Width in pixels of your elements
*/
itemWidth: PropTypes.number.isRequired,
/**
* Width in pixels of the horizontal margin
* between your elements
*/
itemHorizontalMargin: PropTypes.number.isRequired,
/**
* Function returning a react element. The entry
* data is the 1st parameter, its index is the 2nd
Expand All @@ -32,6 +27,14 @@ export default class Carousel extends Component {
* Style of each item's container
*/
slideStyle: PropTypes.number.isRequired,
/**
* Global wrapper's style
*/
containerCustomStyle: PropTypes.number,
/**
* Content container's style
*/
contentContainerCustomStyle: PropTypes.number,
/**
* Delta x when swiping to trigger the snap
*/
Expand All @@ -46,6 +49,14 @@ export default class Carousel extends Component {
* default ones. Can be used w/ animationFunc
*/
animationOptions: PropTypes.object,
/**
* Scale factor of the inactive slides
*/
inactiveSlideScale: PropTypes.number,
/**
* Opacity value of the inactive slides
*/
inactiveSlideOpacity: PropTypes.number,
/**
* Index of the first item to display
*/
Expand Down Expand Up @@ -87,7 +98,11 @@ export default class Carousel extends Component {
animationOptions: {
easing: Easing.elastic(1)
},
slideStyle: {}
slideStyle: {},
containerCustomStyle: null,
contentContainerCustomStyle: null,
inactiveSlideScale: 0.9,
inactiveSlideOpacity: 1
}

constructor (props) {
Expand Down Expand Up @@ -132,11 +147,11 @@ export default class Carousel extends Component {
}

_calcCardPositions (props = this.props) {
const { items, itemWidth, itemHorizontalMargin } = props;
const { items, sliderWidth, itemWidth } = props;

items.forEach((item, index) => {
this._positions[index] = {
start: (itemHorizontalMargin * (index + index === 0 ? 1 : 0)) + (index * itemWidth)
start: index * itemWidth
};
this._positions[index].end = this._positions[index].start + itemWidth;
});
Expand All @@ -163,9 +178,10 @@ export default class Carousel extends Component {
}

_getCenterX (event) {
const { sliderWidth } = this.props;
const { sliderWidth, itemWidth } = this.props;
const containerSideMargin = (sliderWidth - itemWidth) / 2;

return event.nativeEvent.contentOffset.x + sliderWidth / 2;
return event.nativeEvent.contentOffset.x + sliderWidth / 2 - containerSideMargin;
}

_onScroll (event) {
Expand Down Expand Up @@ -248,7 +264,7 @@ export default class Carousel extends Component {
}

get items () {
const { items, renderItem, slideStyle } = this.props;
const { items, renderItem, slideStyle, inactiveSlideScale, inactiveSlideOpacity } = this.props;
if (!this.state.interpolators || !this.state.interpolators.length) {
return false;
}
Expand All @@ -263,12 +279,12 @@ export default class Carousel extends Component {
{transform: [{
scale: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0.85, 1]
outputRange: [inactiveSlideScale, 1]
})
}],
opacity: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0.7, 1]
outputRange: [inactiveSlideOpacity, 1]
})
}
]}>
Expand Down Expand Up @@ -301,27 +317,44 @@ export default class Carousel extends Component {

snapToItem (index, animated = true) {
const itemsLength = this._positions.length;

if (index >= itemsLength) {
index = itemsLength - 1;
} else if (index < 0) {
index = 0;
}

const snapX = this._positions[index].start - ((this.props.sliderWidth - this.props.itemWidth - (2 * this.props.itemHorizontalMargin)) / 2);
const snapX = this._positions[index].start;
this.refs.scrollview.scrollTo({x: snapX, y: 0, animated});
}

render () {
const { sliderWidth, itemWidth, containerCustomStyle, contentContainerCustomStyle } = this.props;

const containerSideMargin = (sliderWidth - itemWidth) / 2;
const style = [
{ paddingHorizontal: Platform.OS === 'ios' ? containerSideMargin : 0 },
containerCustomStyle || {}
];
const contentContainerStyle = [
{ paddingHorizontal: Platform.OS === 'android' ? containerSideMargin : 0 },
contentContainerCustomStyle || {}
];

return (
<ScrollView
{...this.props}
style={style}
contentContainerStyle={contentContainerStyle}
ref={'scrollview'}
horizontal={true}
onScrollBeginDrag={this._onScrollBegin}
onScrollEndDrag={this._onScrollEndDrag}
onResponderRelease={this._onTouchRelease}
onResponderMove={this._onTouchMove}
onScroll={this._onScroll}>
onScroll={this._onScroll}
scrollEventThrottle={50}
>
{ this.items }
</ScrollView>
);
Expand Down

0 comments on commit 2eb3b44

Please sign in to comment.