UNPKG

react-native-swipe-a-lot

Version:

A swipe component for React Native that works on iOS and Android.

195 lines (170 loc) 5.53 kB
import React, { Component, PropTypes } from 'react' import ReactNative from 'react-native' const { Platform, ScrollView, View, ViewPagerAndroid } = ReactNative import Circles from './Circles' import FixedSizeView from './FixedSizeView' import reducer from './reducer' import { createStore } from 'redux' import { EventEmitter } from 'events' export default class SwipeALot extends Component { constructor(props) { super(props) this.store = createStore(reducer) this.emitter = new EventEmitter() this.autoplayInterval = null this.autoplayPageCurrentlyBeingTransitionedTo = 0 } getAutoplaySettings() { // This seems to be the recommended way to setup default props with nested objects // See https://github.com/facebook/react/issues/2568 return Object.assign({ enabled: false, disableOnSwipe: false, delayBetweenAutoSwipes: 5000 }, this.props.autoplay) } componentDidMount() { this.store.dispatch({ type: 'SET_ACTIVE_PAGE', page: 0 }) this.swipeToPageListener = ({ page }) => { this.store.dispatch({ type: 'SET_ACTIVE_PAGE', page }) if (Platform.OS === 'android') { this.swiper.setPage(page) } else { const { width } = this.store.getState() this.swiper.scrollTo({ x: page * width }) } } this.emitter.addListener('swipeToPage', this.swipeToPageListener) if (this.getAutoplaySettings().enabled) { this.startAutoplay() } } componentWillUnmount() { this.emitter.removeListener('swipeToPage', this.swipeToPageListener) } startAutoplay() { if (this.autoplayInterval) return this.autoplayInterval = setInterval(() => { let { page } = this.store.getState() const numOfPages = this.props.children.length || 1 page++ if (page >= numOfPages) page = 0 this.swipeToPage(page) this.autoplayPageCurrentlyBeingTransitionedTo = page }, this.getAutoplaySettings().delayBetweenAutoSwipes) } stopAutoplay() { if (!this.autoplayInterval) return clearInterval(this.autoplayInterval) } getPage() { let { page } = this.store.getState() return page } swipeToPage(page) { this.emitter.emit('swipeToPage', { page }) } static get propTypes() { return { wrapperStyle: PropTypes.object, circleWrapperStyle: PropTypes.object, circleDefaultStyle: PropTypes.object, circleActiveStyle: PropTypes.object, children: PropTypes.any, emitter: PropTypes.object, autoplay: PropTypes.object } } render() { return ( <View style={[this.props.wrapperStyle, {flex: 1}]} onLayout={() => { const page = this.getPage() this.swipeToPage(page) }}> {(() => { if (Platform.OS === 'ios') { return ( <ScrollView ref={(c) => this.swiper = c} pagingEnabled={true} horizontal={true} bounces={false} removeClippedSubviews={true} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} onMomentumScrollEnd={(e) => { const { width } = this.store.getState() const page = e.nativeEvent.contentOffset.x / width this.store.dispatch({ type: 'SET_ACTIVE_PAGE', page: page }) if (this.getAutoplaySettings().disableOnSwipe && this.autoplayPageCurrentlyBeingTransitionedTo !== page) { this.stopAutoplay() } }} onLayout={(event) => { const {x, y, width, height} = event.nativeEvent.layout this.store.dispatch({ type: 'SET_DIMS', width, height }) }} automaticallyAdjustContentInsets={false}> {React.Children.map(this.props.children, (c, i) => { return <FixedSizeView store={this.store} key={`view${i}`}>{c}</FixedSizeView> })} </ScrollView> ) } else if (Platform.OS === 'android') { return ( <ViewPagerAndroid ref={(c) => this.swiper = c} initialPage={0} onPageSelected={(e) => { this.store.dispatch({ type: 'SET_ACTIVE_PAGE', page: e.nativeEvent.position }) if (this.getAutoplaySettings().disableOnSwipe && this.autoplayPageCurrentlyBeingTransitionedTo !== e) { this.stopAutoplay() } }} style={{ flex: 1 }}> {React.Children.map(this.props.children, (c) => { return <View>{c}</View> })} </ViewPagerAndroid> ) } })()} <Circles store={this.store} emitter={this.emitter} circleWrapperStyle={this.props.circleWrapperStyle} circleDefaultStyle={this.props.circleDefaultStyle} circleActiveStyle={this.props.circleActiveStyle}> {this.props.children} </Circles> </View> ) } }