Skip to content

Commit

Permalink
Merge pull request #30 from archriss/update-rendering
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Use direct children as slides
  • Loading branch information
bd-arc authored Feb 2, 2017
2 parents 9d99a74 + f5e9b59 commit e13304b
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 204 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## v2.0.0

* Items are now direct children of the <Carousel> component, which makes it easier to use (thanks [@Jonarod](https://github.com/Jonarod) !)
* Props `items` and `renderItem` have been removed

## v1.6.1

* Due to some touch events being buggy, rework methods so the children will receive touch events on Android.
* Due to some touch events being buggy, rework methods so the children will receive touch events on Android

## v1.6.0

Expand Down
77 changes: 49 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,46 @@ This app is going to be updated on a regular basis.

## Usage

### Breaking change
Since version 2.0.0, items are now **direct children of the <Carousel> component**. As a result, props `items` and `renderItem` have been removed.

```
$ npm install --save react-native-snap-carousel
```

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

_renderItem (data, index) {
return (
...
);
// Example with different children
render () {
<Carousel
ref={'carousel'}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
>
<View style={styles.slide1} />
<ListView style={styles.slide2} />
<Image style={styles.slide3} />
</Carousel>
}

// Example of appending the same component multiple times while looping through an array of data
render () {
const slides = this.state.entries.map((entry, index) => {
return (
<View key={`entry-${index}`} style={styles.slide}>
<Text style={styles.title}>{ entry.title }</Text>
</View>
);
});

<Carousel
ref={'carousel'}
items={this.state.entries}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
slideStyle={styles.slide} />
>
{ slides }
</Carousel>
}
```

Expand All @@ -57,27 +76,25 @@ import Carousel from 'react-native-snap-carousel';
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
renderItem | Function returning a react element. The entry data is the 1st parameter, its index is the 2nd | Function | Required
shouldOptimizeUpdates | whether to implement a `shouldComponentUpdate` strategy to minimize updates | Boolean | `true`
slideStyle | Style of each item's container | Number | Required
swipeThreshold | Delta x when swiping to trigger the snap | Number | `20`
animationFunc | Animated animation to use. Provide the name of the method | String | `Timing`
**itemWidth** | Width in pixels of your items | Number | **Required**
**sliderWidth** | The width in pixels of your slider | Number | **Required**
animationFunc | Animated animation to use. Provide the name of the method | String | `timing`
animationOptions | Animation options to be merged with the default ones. Can be used w/ animationFunc | Object | `{ easing: Easing.elastic(1) }`
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 | Delay before enabling autoplay on startup & after releasing the touch | Number | `5000`
autoplayInterval | Delay in ms until navigating to the next item | `3000`
containerCustomStyle | Optional styles for Scrollview's global wrapper | ScrollView Style Object | `{}`
contentContainerCustomStyle | Optional styles for Scrollview's items container | ScrollView Style Object | `{}`
enableMomentum | See [momentum](#momentum) | Boolean | `false`
enableSnap | If enabled, releasing the touch will scroll to the center of the nearest/active item | Number | `true`
enableMomentum | See [momentum](#momentum) | Boolean | `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`
firstItem | Index of the first item to display | Number | `0`
inactiveSlideOpacity | Value of the opacity effect applied to inactive slides | Number | `1`
onSnapToItem(slideIndex, itemData) | Callback fired when navigating to an item | Function | `undefined`
inactiveSlideScale | Value of the 'scale' transform applied to inactive slides | Number | `0.9`
shouldOptimizeUpdates | whether to implement a `shouldComponentUpdate` strategy to minimize updates | Boolean | `true`
slideStyle | Optional style for each item's container (the one whose scale and opacity are animated) | Animated View Style Object | {}
snapOnAndroid | Snapping on android is kinda choppy, especially when swiping quickly so you can disable it | Boolean | `true`
swipeThreshold | Delta x when swiping to trigger the snap | Number | `20`
onSnapToItem(slideIndex) | Callback fired when navigating to an item | Function | `undefined`

## Methods

Expand Down Expand Up @@ -109,8 +126,9 @@ You can adjust this value to your needs thanks to [this prop](https://facebook.g
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 sliderWidth = Dimensions.get('window').width * 0.75;
const slideWidth = 250;
const horizontalMargin = 40;
const horizontalMargin = 20;
const itemWidth = slideWidth + horizontalMargin * 2;

const styles = Stylesheet.create({
Expand All @@ -121,16 +139,19 @@ const styles = Stylesheet.create({
};

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

```
## TODO
- [ ] Add 'loop' mode
- [ ] Add 'preload' mode
- [ ] Known issue: updating children's length doesn't play well with autoplay
- [ ] Implement 'loop' mode
- [ ] Implement 'preload' mode
- [ ] Handle changing props on-the-fly
- [ ] Handle device orientation event
- [ ] Add vertical implementation
Expand Down
4 changes: 2 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "example",
"version": "0.0.1",
"version": "0.2.0",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
Expand All @@ -9,7 +9,7 @@
"dependencies": {
"react": "15.4.1",
"react-native": "0.38.0",
"react-native-snap-carousel": "1.6.1"
"react-native-snap-carousel": "2.0.0"
},
"jest": {
"preset": "react-native"
Expand Down
20 changes: 13 additions & 7 deletions example/src/components/SliderEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,33 @@ export default class SliderEntry extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string,
illustration: PropTypes.string
illustration: PropTypes.string,
even: PropTypes.bool
};

render () {
const { title, subtitle, illustration } = this.props;
const { title, subtitle, illustration, even } = this.props;

const uppercaseTitle = title ? (
<Text style={[styles.title, even ? styles.titleEven : {}]} numberOfLines={2}>{ title.toUpperCase() }</Text>
) : false;

return (
<TouchableOpacity
activeOpacity={0.9}
activeOpacity={0.7}
style={styles.slideInnerContainer}
onPress={() => { alert(`You've clicked '${title}'`); }}
>
<View style={styles.imageContainer}>
<View style={[styles.imageContainer, even ? styles.imageContainerEven : {}]}>
<Image
source={{ uri: illustration }}
style={styles.image}
/>
<View style={[styles.radiusMask, even ? styles.radiusMaskEven : {}]} />
</View>
<View style={styles.textContainer}>
<Text style={styles.title} numberOfLines={2}>{ title.toUpperCase() }</Text>
<Text style={styles.subtitle} numberOfLines={2}>{ subtitle }</Text>
<View style={[styles.textContainer, even ? styles.textContainerEven : {}]}>
{ uppercaseTitle }
<Text style={[styles.subtitle, even ? styles.subtitleEven : {}]} numberOfLines={2}>{ subtitle }</Text>
</View>
</TouchableOpacity>
);
Expand Down
76 changes: 45 additions & 31 deletions example/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,87 @@ import { View, ScrollView, Text, StatusBar } from 'react-native';
import Carousel from 'react-native-snap-carousel';
import { sliderWidth, itemWidth } from 'example/src/styles/SliderEntry.style';
import SliderEntry from 'example/src/components/SliderEntry';
import mainStyles from 'example/src/styles/index.style';
import sliderStyles from 'example/src/styles/Slider.style';
import styles from 'example/src/styles/index.style';
import { ENTRIES1, ENTRIES2 } from 'example/src/static/entries';

export default class example extends Component {

_renderItem (entry) {
return (
<SliderEntry {...entry} />
);
getSlides (entries) {
if (!entries) {
return false;
}

return entries.map((entry, index) => {
return (
<SliderEntry
key={`carousel-entry-${index}`}
even={(index + 1) % 2 === 0}
{...entry}
/>
);
});
}

get example1 () {
return (
<Carousel
items={ENTRIES1}
firstItem={2}
inactiveSlideScale={0.94}
inactiveSlideOpacity={0.6}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
slideStyle={sliderStyles.slide}
containerCustomStyle={sliderStyles.slider}
contentContainerCustomStyle={sliderStyles.sliderContainer}
firstItem={1}
inactiveSlideScale={0.94}
inactiveSlideOpacity={0.6}
enableMomentum={true}
containerCustomStyle={styles.slider}
contentContainerCustomStyle={styles.sliderContainer}
showsHorizontalScrollIndicator={false}
snapOnAndroid={true}
removeClippedSubviews={false}
/>
>
{ this.getSlides(ENTRIES1) }
</Carousel>
);
}

get example2 () {
return (
<Carousel
items={ENTRIES2}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
inactiveSlideScale={1}
inactiveSlideOpacity={1}
enableMomentum={false}
enableMomentum={false}
autoplay={true}
autoplayDelay={500}
autoplayInterval={2500}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
slideStyle={sliderStyles.slide}
containerCustomStyle={sliderStyles.slider}
contentContainerCustomStyle={sliderStyles.sliderContainer}
containerCustomStyle={styles.slider}
contentContainerCustomStyle={styles.sliderContainer}
showsHorizontalScrollIndicator={false}
snapOnAndroid={true}
removeClippedSubviews={false}
/>
>
{ this.getSlides(ENTRIES2) }
</Carousel>
);
}

render () {
return (
<View style={mainStyles.container}>
<View style={styles.container}>
<StatusBar backgroundColor={'transparent'} barStyle={'light-content'} />
<View style={mainStyles.colorsContainer}>
<View style={mainStyles.color1} />
<View style={mainStyles.color2} />
<View style={styles.colorsContainer}>
<View style={styles.color1} />
<View style={styles.color2} />
</View>
<ScrollView style={mainStyles.scrollview}>
<Text style={mainStyles.title}>Example 1</Text>
<ScrollView
style={styles.scrollview}
indicatorStyle={'white'}
scrollEventThrottle={200}
>
<Text style={styles.title}>Example 1</Text>
<Text style={styles.subtitle}>Momentum | Scale | Opacity</Text>
{ this.example1 }
<Text style={mainStyles.title}>Example 2 (no momentum)</Text>
<Text style={styles.title}>Example 2</Text>
<Text style={styles.subtitle}>Autoplay | No momentum</Text>
{ this.example2 }
</ScrollView>
</View>
Expand Down
15 changes: 0 additions & 15 deletions example/src/styles/Slider.style.js

This file was deleted.

Loading

0 comments on commit e13304b

Please sign in to comment.