UNPKG

react-native-banner-carousel-updated

Version:
341 lines (340 loc) 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const React = require("react"); const react_native_1 = require("react-native"); class Carousel extends React.Component { constructor(props) { super(props); this.autoPlayTimer = 0; this.currentIndex = 0; this.panStartIndex = 0; this.panOffsetFactor = 0; this.verticalScrollDisabled = false; this.state = { scrollValue: new react_native_1.Animated.Value(0) }; } UNSAFE_componentWillMount() { if (!this.props.disableUserInteraction) { this.panResponder = react_native_1.PanResponder.create({ onStartShouldSetPanResponder: () => { this.startPanResponder(); return true; }, onShouldBlockNativeResponder: (e, g) => { return !this.props.changeVerticalScrollEnabled; }, onMoveShouldSetPanResponder: (e, g) => { if (Math.abs(g.dx) > Math.abs(g.dy)) { this.startPanResponder(); return true; } else { return false; } }, onPanResponderTerminationRequest: () => { return false; }, onPanResponderGrant: () => { this.startPanResponder(); }, onPanResponderStart: (e, g) => { this.startPanResponder(); }, onPanResponderMove: (e, g) => { var _a, _b; if (Math.abs(g.dx) > Math.abs(g.dy) && !this.verticalScrollDisabled) { (_b = (_a = this.props).changeVerticalScrollEnabled) === null || _b === void 0 ? void 0 : _b.call(_a, false); this.verticalScrollDisabled = true; } this.panOffsetFactor = this.computePanOffset(g); this.gotoPage(this.panStartIndex + this.panOffsetFactor, false); }, onPanResponderEnd: (e, g) => { var _a, _b, _c, _d; if (g.dx == 0 && g.dy == 0) { (_b = (_a = this.props).onPress) === null || _b === void 0 ? void 0 : _b.call(_a); } this.verticalScrollDisabled = false; (_d = (_c = this.props).changeVerticalScrollEnabled) === null || _d === void 0 ? void 0 : _d.call(_c, true); this.endPanResponder(g); this.scrollView.scrollTo({ x: 0, animated: false }); } }); } } componentDidMount() { if (this.props.autoplay) { this.startAutoPlay(); } this.gotoPage(this.props.index + (this.props.loop ? 1 : 0), false); } UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.autoplay) { this.startAutoPlay(); } else { this.stopAutoPlay(); } } startAutoPlay() { this.stopAutoPlay(); if (!this.autoPlayTimer) { this.autoPlayTimer = setInterval(() => { this.gotoNextPage(); }, this.props.autoplayTimeout); } } stopAutoPlay() { if (this.autoPlayTimer) { clearInterval(this.autoPlayTimer); this.autoPlayTimer = 0; } } computePanOffset(g) { let offset = -g.dx / (this.props.pageSize / this.props.slipFactor); if (Math.abs(offset) > 1) { offset = offset > 1 ? 1 : -1; } return offset; } startPanResponder() { this.stopAutoPlay(); this.panStartIndex = this.currentIndex; this.panOffsetFactor = 0; if (this.pageAnimation) { const index = this.currentIndex; this.pageAnimation.stop(); this.gotoPage(index); } } endPanResponder(g) { if (this.props.autoplay) { this.startAutoPlay(); } let newIndex = this.currentIndex; this.panOffsetFactor = this.computePanOffset(g); if (this.panOffsetFactor > 0.5 || (this.panOffsetFactor > 0 && g.vx <= -0.1)) { newIndex = Math.floor(this.currentIndex + 1); } else if (this.panOffsetFactor < -0.5 || (this.panOffsetFactor < 0 && g.vx >= 0.1)) { newIndex = Math.ceil(this.currentIndex - 1); } else { newIndex = Math.round(this.currentIndex); } if (this.currentIndex === newIndex) { return; } this.gotoPage(newIndex); } gotoNextPage(animated = true) { const childrenNum = this.getChildrenNum(); if (!this.props.loop) { if (this.currentIndex === childrenNum - 1) { return; } } this.gotoPage(Math.floor(this.currentIndex) + 1); } gotoPage(index, animated = true, cb = () => { }) { const childrenNum = this.getChildrenNum(); if (childrenNum <= 1) { return cb(); } if (index < 0) { index = 0; } if (index > childrenNum - 1) { index = childrenNum - 1; } const setIndex = (index) => { this.currentIndex = index; if (this.props.onPageChanged && Number.isInteger(this.currentIndex)) { this.props.onPageChanged(this.getCurrentPage()); } }; if (animated) { this.pageAnimation = this.props.animation(this.state.scrollValue, index); const animationId = this.state.scrollValue.addListener((state) => { setIndex(state.value); }); this.pageAnimation.start(() => { this.state.scrollValue.removeListener(animationId); setIndex(index); this.pageAnimation = null; this.loopJump(); cb(); }); } else { this.state.scrollValue.setValue(index); setIndex(index); this.loopJump(); cb(); } } /** * -0.5 <= pageIndex <= (pages.length - 1 + 0.5) */ getCurrentPage() { const childrenNum = this.getChildrenNum(); if (childrenNum <= 1) { return childrenNum; } const index = this.currentIndex; if (this.props.loop) { if (index < 0.5) { return index + childrenNum - 2 - 1; } else if (index > childrenNum - 2 + 0.5) { return index - childrenNum + 1; } else { return index - 1; } } else { return index; } } loopJump() { if (!this.props.loop) { return; } const childrenNum = this.getChildrenNum(); if (childrenNum <= 1) { return; } if (this.currentIndex === 0) { this.gotoPage(childrenNum - 2, false); } else if (this.currentIndex === (childrenNum - 1)) { this.gotoPage(1, false); } } getChildrenNum() { const { children, loop } = this.props; let pages = React.Children.toArray(children); if (pages.length < 2) { return 1; } if (loop) { return pages.length + 2; } else { return pages.length; } } renderIndicator(config) { if (!this.props.showsPageIndicator) { return null; } if (this.props.renderPageIndicator) { return this.props.renderPageIndicator(config); } const { childrenNum, pageNum, loop, scrollValue } = config; if (pageNum === 0) { return null; } const indicators = []; for (let i = 0; i < pageNum; i++) { indicators.push(React.createElement(react_native_1.View, { key: i, style: [styles.pageIndicatorStyle, this.props.pageIndicatorStyle] })); } const offset = this.props.pageIndicatorOffset; let left; if (pageNum === 1) { left = this.state.scrollValue.interpolate({ inputRange: [0, 1], outputRange: [0, 0] }); } else if (!loop) { left = this.state.scrollValue.interpolate({ inputRange: [0, 1], outputRange: [0, offset] }); } else { left = this.state.scrollValue.interpolate({ inputRange: [0, 1, 2, childrenNum - 2, childrenNum - 1], outputRange: [0, 0, offset, offset * (childrenNum - 3), offset * (childrenNum - 3)] }); } return (React.createElement(react_native_1.View, { style: [styles.pageIndicatorContainerStyle, this.props.pageIndicatorContainerStyle] }, indicators, React.createElement(react_native_1.Animated.View, { style: [ styles.pageIndicatorStyle, styles.activePageIndicatorStyle, this.props.pageIndicatorStyle, this.props.activePageIndicatorStyle, { left: left } ] }))); } render() { var _a; const { children, pageSize, loop } = this.props; const { scrollValue } = this.state; let pages = React.Children.toArray(children); const pageNum = pages.length; if (loop && pages.length > 1) { pages.unshift(pages[pages.length - 1]); pages.push(pages[1]); } pages = pages.map((page, index) => { return (React.createElement(react_native_1.View, { key: index, style: { width: pageSize } }, page)); }); const childrenNum = pages.length; let content; if (childrenNum < 1) { content = null; } else { const translateX = scrollValue.interpolate({ inputRange: [0, 1, childrenNum], outputRange: [0, -pageSize, -childrenNum * pageSize] }); content = (React.createElement(react_native_1.Animated.View, Object.assign({ style: { flexDirection: 'row', width: pageSize * childrenNum, transform: [{ translateX }] } }, (_a = this.panResponder) === null || _a === void 0 ? void 0 : _a.panHandlers), pages)); } return (React.createElement(react_native_1.View, null, React.createElement(react_native_1.ScrollView, { ref: ref => this.scrollView = ref, style: { width: pageSize }, contentContainerStyle: { width: pageSize + 1 }, horizontal: true, pagingEnabled: true, directionalLockEnabled: true, bounces: false, alwaysBounceHorizontal: false, alwaysBounceVertical: false, showsVerticalScrollIndicator: false, showsHorizontalScrollIndicator: false, scrollEnabled: react_native_1.Platform.OS === 'ios' ? !this.props.disableUserInteraction : false }, content), this.renderIndicator({ childrenNum, pageNum, loop, scrollValue }))); } } exports.default = Carousel; Carousel.defaultProps = { pageSize: react_native_1.Dimensions.get('window').width, index: 0, loop: true, autoplay: true, autoplayTimeout: 5000, slipFactor: 1, showsPageIndicator: true, pageIndicatorOffset: 16, animation: (animate, toValue) => { return react_native_1.Animated.spring(animate, { toValue: toValue, friction: 10, tension: 50, useNativeDriver: false }); } }; const styles = react_native_1.StyleSheet.create({ pageIndicatorStyle: { width: 6, height: 6, borderRadius: 3, marginHorizontal: 5, backgroundColor: 'rgba(0,0,0,.4)' }, activePageIndicatorStyle: { position: 'absolute', backgroundColor: '#ffc81f', }, pageIndicatorContainerStyle: { position: 'absolute', alignSelf: 'center', flexDirection: 'row', bottom: 10 } });