Maintained Version of @meteor-factory's package.
npm install --save react-native-swipeable-cards
- Create a module e.g.
SwipeCards.js
- Import it
import SwipeCards from 'react-native-swipeable-cards'
- Render it
<SwipeCards style={{flex: 1}} />
// SwipeCards.js
'use strict';
import React, { Component } from 'react';
import {StyleSheet, Text, View, Image} from 'react-native';
import SwipeCards from 'react-native-swipeable-cards';
class Card extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={[styles.card, {backgroundColor: this.props.backgroundColor}]}>
<Text>{this.props.text}</Text>
</View>
)
}
}
class NoMoreCards extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View>
<Text style={styles.noMoreCardsText}>No more cards</Text>
</View>
)
}
}
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: [
{text: 'Tomato', backgroundColor: 'red'},
{text: 'Aubergine', backgroundColor: 'purple'},
{text: 'Courgette', backgroundColor: 'green'},
{text: 'Blueberry', backgroundColor: 'blue'},
{text: 'Umm...', backgroundColor: 'cyan'},
{text: 'orange', backgroundColor: 'orange'},
]
};
}
onSwipeRight (card) {
console.log(`Yup for ${card.text}`)
}
onSwipeLeft (card) {
console.log(`Nope for ${card.text}`)
}
onSwipeUp (card) {
console.log(`Maybe for ${card.text}`)
}
render() {
// If you want a stack of cards instead of one-per-one view, activate stack mode
// stack={true}
return (
<SwipeCards
cards={this.state.cards}
renderCard={(cardData) => <Card {...cardData} />}
renderNoMoreCards={() => <NoMoreCards />}
onSwipeRight={this.handleYup}
onSwipeLeft={this.handleNope}
onSwipeUp={this.handleMaybe}
hasMaybeAction
/>
)
}
}
const styles = StyleSheet.create({
card: {
justifyContent: 'center',
alignItems: 'center',
width: 300,
height: 300,
},
noMoreCardsText: {
fontSize: 22,
}
})
'use strict';
import React, { Component } from 'react';
import {StyleSheet, Text, View, Image} from 'react-native';
import SwipeCards from 'react-native-swipeable-cards';
class Card extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.card}>
<Image style={styles.thumbnail} source={{uri: this.props.image}} />
<Text style={styles.text}>This is card {this.props.name}</Text>
<Button type='outline' title='Nah'
style={SwipeStyles.rejectButton}
onPress={() => {
this.props.swiper._forceNextCard()
}}
/>
</View>
)
}
}
class NoMoreCards extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.noMoreCards}>
<Text>No more cards</Text>
</View>
)
}
}
const cards = [
{name: '1', image: 'https://media.giphy.com/media/GfXFVHUzjlbOg/giphy.gif'},
{name: '2', image: 'https://media.giphy.com/media/irTuv1L1T34TC/giphy.gif'},
{name: '3', image: 'https://media.giphy.com/media/LkLL0HJerdXMI/giphy.gif'},
{name: '4', image: 'https://media.giphy.com/media/fFBmUMzFL5zRS/giphy.gif'},
{name: '5', image: 'https://media.giphy.com/media/oDLDbBgf0dkis/giphy.gif'},
{name: '6', image: 'https://media.giphy.com/media/7r4g8V2UkBUcw/giphy.gif'},
{name: '7', image: 'https://media.giphy.com/media/K6Q7ZCdLy8pCE/giphy.gif'},
{name: '8', image: 'https://media.giphy.com/media/hEwST9KM0UGti/giphy.gif'},
{name: '9', image: 'https://media.giphy.com/media/3oEduJbDtIuA2VrtS0/giphy.gif'},
]
const cards2 = [
{name: '10', image: 'https://media.giphy.com/media/12b3E4U9aSndxC/giphy.gif'},
{name: '11', image: 'https://media4.giphy.com/media/6csVEPEmHWhWg/200.gif'},
{name: '12', image: 'https://media4.giphy.com/media/AA69fOAMCPa4o/200.gif'},
{name: '13', image: 'https://media.giphy.com/media/OVHFny0I7njuU/giphy.gif'},
]
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: cards,
outOfCards: false
}
}
cardSwipedRight (card) {
console.log("LIKED!")
}
cardSwipedLeft (card) {
console.log("DISLIKED!")
}
cardRemoved (index) {
console.log(`The index is ${index}`);
let CARD_REFRESH_LIMIT = 3
if (this.state.cards.length - index <= CARD_REFRESH_LIMIT + 1) {
console.log(`There are only ${this.state.cards.length - index - 1} cards left.`);
if (!this.state.outOfCards) {
console.log(`Adding ${cards2.length} more cards`)
this.setState({
cards: this.state.cards.concat(cards2),
outOfCards: true
})
}
}
}
render() {
return (
<SwipeCards
cards={this.state.cards}
ref = {(swiper) => this.swiper = swiper}
loop={false}
renderCard={(cardData) => <Card swiper={this.swiper} {...cardData} />}
renderNoMoreCards={() => <NoMoreCards />}
showRightOverlay={true}
showLeftOverlay={true}
stackDepth={3}
stack={true}
keyExtractor={(card) => {
return card.name
}}
onSwipeRight={this.cardSwipedRight}
onSwipeLeft={this.cardSwipedLeft}
cardRemoved={(card) => this.cardRemoved(card)}
/>
)
}
}
const styles = StyleSheet.create({
card: {
alignItems: 'center',
borderRadius: 5,
overflow: 'hidden',
borderColor: 'grey',
backgroundColor: 'white',
borderWidth: 1,
elevation: 1,
},
thumbnail: {
width: 300,
height: 300,
},
text: {
fontSize: 20,
paddingTop: 10,
paddingBottom: 10
},
noMoreCards: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
Props name | Type | Description | Default |
---|---|---|---|
cards* | Array | Data that will be provided as props for the cards | |
renderCard* | Function | Renders the card with the current data | |
loop | Boolean | If true, start again when run out of cards | false |
onLoop | Function | Called when card list returns to the beginning | |
renderNoMoreCards | Function | Renders what is shown after swiped last card | |
showRightOverlay | Boolean | Shows the 'Right Overlay' component | true |
showLeftOverlay | Boolean | Shows the 'Left Overlay' | true |
showUpOverlay | Boolean | Shows the 'Up Overlay' | true |
swipeUp | Boolean | Includes the possibility to swipe up and its components | false |
renderRightOverlay | Function | Renders the Right Overlay | |
renderLeftOverlay | Function | Renders Left Overlay | |
renderUpOverlay | Function | Renders Up Overlay | |
onSwipeRight | Function | Called when card is 'passed' with that card's data | |
onSwipeLeft | Function | Called when card is 'rejected' with that card's data | |
containerStyle | style | Override default style | |
overlayRightWrapper | style | Override default style | |
overlayRightTextStyle | style | Override default style | |
overlayLeftWrapper | style | Override default style | |
overlayLeftTextStyle | style | Override default style | |
overlayUpWrapper | style | Override default style | |
overlayUpTextStyle | style | Override default style | |
overlayRight | element | React component to render on a Yes vote | |
overlayRightText | string | Text to render on Yes vote | Like |
overlayLeft | element | React component to render on a No vote | |
overlayLeftText | string | Text to render on No vote | Nope |
overlayUp | element | React component to render on a Maybe vote | |
overlayUpText | string | Text to render on Maybe vote | Maybe |
smoothTransition | Boolean | Disables a slow transition fading the current card out | false |
cardKey | String | React key to be used to for each card | |
dragY | Boolean | Allows dragging cards vertically | true |
stack | Boolean | Enables the stack mode | false |
stackDepth | Number | Number of Cards for Stack to Container | 5 |
stackOffsetX | Number | Horizontal offset between cards in stack | 25 |
stackOffsetY | Number | Vertical offset between cards in stack | 0 |
cardRemoved | Function | A callback passing the card reference that just got removed | |
onClickHandler | Function | A callback clicking the card | alert('tap') |
keyExtractor | Function | Callback to set Key prop on card | key = index |
rotation | Boolean | Disable card rotation during swipe | True |
*required
- Show next card underneath current card
- Add more args to
cardRemoved
? - Update ReadMe