UNPKG

@ant-design/react-native

Version:

基于蚂蚁金服移动设计规范的 React Native 组件库

469 lines (432 loc) 19 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactNative = require('react-native'); var _style = require('../style'); var _index2 = require('./style/index'); var _index3 = _interopRequireDefault(_index2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var defaultPagination = function defaultPagination(props) { var styles = props.styles, current = props.current, vertical = props.vertical, count = props.count, dotStyle = props.dotStyle, dotActiveStyle = props.dotActiveStyle; var positionStyle = vertical ? 'paginationY' : 'paginationX'; var flexDirection = vertical ? 'column' : 'row'; var arr = []; for (var i = 0; i < count; i++) { arr.push(_react2['default'].createElement(_reactNative.View, { key: 'dot-' + i, style: [styles.pointStyle, styles.spaceStyle, dotStyle, i === current && styles.pointActiveStyle, i === current && dotActiveStyle] })); } return _react2['default'].createElement( _reactNative.View, { style: [styles.pagination, styles[positionStyle]] }, _react2['default'].createElement( _reactNative.View, { style: { flexDirection: flexDirection } }, arr ) ); }; var Carousel = function (_React$Component) { (0, _inherits3['default'])(Carousel, _React$Component); function Carousel(props) { (0, _classCallCheck3['default'])(this, Carousel); var _this = (0, _possibleConstructorReturn3['default'])(this, (Carousel.__proto__ || Object.getPrototypeOf(Carousel)).call(this, props)); _this.getChildrenCount = function (children) { var count = children ? _react2['default'].Children.count(children) || 1 : 0; return count; }; _this.loopJump = function () { var _this$state = _this.state, loopJump = _this$state.loopJump, selectedIndex = _this$state.selectedIndex, width = _this$state.width, height = _this$state.height; var _this$props = _this.props, infinite = _this$props.infinite, vertical = _this$props.vertical; // iOS 通过 contentOffet 可以平滑过度,不需要做处理 if (loopJump && _reactNative.Platform.OS === 'android') { var _index = selectedIndex + (infinite ? 1 : 0); var x = 0; var y = 0; if (vertical) { y = height * _index; } else { x = width * _index; } // FIXME: not work well in android when horizontal setTimeout(function () { // tslint:disable-next-line:no-unused-expression _this.scrollviewRef && _this.scrollviewRef.scrollTo({ x: x, y: y, animated: false }); }, 10); } }; _this.autoplay = function () { var _this$props2 = _this.props, children = _this$props2.children, autoplay = _this$props2.autoplay, infinite = _this$props2.infinite, autoplayInterval = _this$props2.autoplayInterval; var _this$state2 = _this.state, isScrolling = _this$state2.isScrolling, autoplayEnd = _this$state2.autoplayEnd, selectedIndex = _this$state2.selectedIndex; var count = _this.getChildrenCount(children); if (!Array.isArray(children) || !autoplay || isScrolling || autoplayEnd) { return; } clearTimeout(_this.autoplayTimer); _this.autoplayTimer = setTimeout(function () { if (!infinite && selectedIndex === count - 1) { // !infinite && last one, autoplay end return _this.setState({ autoplayEnd: true }); } _this.scrollNextPage(); }, autoplayInterval); }; _this.onScrollBegin = function (e) { _this.setState({ isScrolling: true }, function () { if (_this.props.onScrollBeginDrag) { _this.props.onScrollBeginDrag(e, _this.state, _this); } }); }; _this.onScrollEnd = function (e) { _this.setState({ isScrolling: false }); // android incompatible if (!e.nativeEvent.contentOffset) { // kind of hack ? see: line 282 var position = e.nativeEvent.position; e.nativeEvent.contentOffset = { x: position * _this.state.width, y: position * _this.state.height }; } _this.updateIndex(e.nativeEvent.contentOffset); _this.scrollEndTimter = setTimeout(function () { _this.autoplay(); _this.loopJump(); if (_this.props.onMomentumScrollEnd) { _this.props.onMomentumScrollEnd(e, _this.state, _this); } }); }; _this.onScrollEndDrag = function (e) { var _this$state3 = _this.state, offset = _this$state3.offset, selectedIndex = _this$state3.selectedIndex; var _this$props3 = _this.props, vertical = _this$props3.vertical, children = _this$props3.children; var previousOffset = vertical ? offset.y : offset.x; var newOffset = vertical ? e.nativeEvent.contentOffset.y : e.nativeEvent.contentOffset.x; var count = _this.getChildrenCount(children); if (previousOffset === newOffset && (selectedIndex === 0 || selectedIndex === count - 1)) { _this.setState({ isScrolling: false }); } // pagingEnabled: Vertical pagination is not supported on Android. // implement android vertical paging // if upgrade rn to 0.53, can use snapToInterval to implement vertical paging _this.paging(e.nativeEvent.contentOffset.y); }; _this.paging = function (offsetY) { var height = _this.state.height; var _this$props4 = _this.props, vertical = _this$props4.vertical, infinite = _this$props4.infinite; if (_reactNative.Platform.OS === 'android' && vertical) { var _selectedIndex = Math.round(offsetY / height) - (infinite ? 1 : 0); // tslint:disable-next-line:no-unused-expression _this.scrollviewRef && _this.scrollviewRef.scrollTo({ x: 0, y: (_selectedIndex + (infinite ? 1 : 0)) * height }); // if drag ScrollView, not slide ScrollView, onScrollEnd is not triggered, so need to manually trigger onScrollEnd if (_reactNative.Platform.OS === 'android' && vertical) { _this.onScrollEnd({ nativeEvent: { position: _selectedIndex + (infinite ? 1 : 0) } }); } } }; _this.updateIndex = function (offset) { var _this$props5 = _this.props, vertical = _this$props5.vertical, children = _this$props5.children, infinite = _this$props5.infinite, afterChange = _this$props5.afterChange; var _this$state4 = _this.state, _this$state4$offset = _this$state4.offset, x = _this$state4$offset.x, y = _this$state4$offset.y, height = _this$state4.height, width = _this$state4.width; var selectedIndex = _this.state.selectedIndex; var diff = vertical ? offset.y - y : offset.x - x; var step = vertical ? height : width; var loopJump = false; var count = _this.getChildrenCount(children); // Do nothing if offset no change. if (!diff) { return; } selectedIndex = selectedIndex + Math.round(diff / step); if (infinite) { if (selectedIndex <= -1) { selectedIndex = count - 1; if (vertical) { offset.y = step * count; } else { offset.x = step * count; } loopJump = true; } else if (selectedIndex >= count) { selectedIndex = 0; if (vertical) { offset.y = step; } else { offset.x = step; } loopJump = true; } } _this.setState({ selectedIndex: selectedIndex, offset: offset, loopJump: loopJump }); if (afterChange) { afterChange(selectedIndex); } }; _this.scrollNextPage = function () { var _this$state5 = _this.state, isScrolling = _this$state5.isScrolling, selectedIndex = _this$state5.selectedIndex, width = _this$state5.width, height = _this$state5.height; var _this$props6 = _this.props, children = _this$props6.children, infinite = _this$props6.infinite, vertical = _this$props6.vertical; var count = _this.getChildrenCount(children); if (isScrolling || count < 2) { return; } var diff = (infinite ? 1 : 0) + selectedIndex + 1; if (vertical) { // tslint:disable-next-line:no-unused-expression _this.scrollviewRef && _this.scrollviewRef.scrollTo({ x: 0, y: diff * height }); } else { // tslint:disable-next-line:no-unused-expression _this.scrollviewRef && _this.scrollviewRef.scrollTo({ x: diff * width, y: 0 }); } _this.setState({ isScrolling: true, autoplayEnd: false }); // trigger onScrollEnd manually in android if (_reactNative.Platform.OS === 'android') { _this.androidScrollEndTimer = setTimeout(function () { _this.onScrollEnd({ nativeEvent: { position: diff } }); }, 0); } }; _this.renderContent = function (pages) { var others = { onScrollBeginDrag: _this.onScrollBegin, onMomentumScrollEnd: _this.onScrollEnd, onScrollEndDrag: _this.onScrollEndDrag }; return _react2['default'].createElement( _reactNative.ScrollView, (0, _extends3['default'])({ ref: function ref(el) { return _this.scrollviewRef = el; } }, _this.props, { horizontal: !_this.props.vertical, pagingEnabled: true, bounces: !!_this.props.bounces, scrollEventThrottle: 100, removeClippedSubviews: false, automaticallyAdjustContentInsets: false, directionalLockEnabled: true, showsHorizontalScrollIndicator: false, showsVerticalScrollIndicator: false, contentContainerStyle: _this.props.style, contentOffset: _this.state.offset }, others), pages ); }; _this.renderDots = function (index) { var _this$props7 = _this.props, children = _this$props7.children, vertical = _this$props7.vertical, pagination = _this$props7.pagination, dotStyle = _this$props7.dotStyle, dotActiveStyle = _this$props7.dotActiveStyle; if (!pagination) { return null; } var count = _this.getChildrenCount(children); return _react2['default'].createElement( _style.WithTheme, { themeStyles: _index3['default'], styles: _this.props.styles }, function (styles) { return pagination({ styles: styles, vertical: vertical, current: index, count: count, dotStyle: dotStyle, dotActiveStyle: dotActiveStyle }); } ); }; _this.onLayout = function (e) { // for horizontal, get width, scollTo // for vertical, get height, scollTo var _this$props8 = _this.props, children = _this$props8.children, infinite = _this$props8.infinite, vertical = _this$props8.vertical; var count = _this.getChildrenCount(children); var selectedIndex = count > 1 ? Math.min(_this.props.selectedIndex, count - 1) : 0; var width = e.nativeEvent.layout.width; var offsetX = vertical ? 0 : width * (selectedIndex + (infinite ? 1 : 0)); var offsetY = vertical ? _this.state.height * (selectedIndex + (infinite ? 1 : 0)) : 0; _this.setState({ width: width, offset: { x: offsetX, y: offsetY } }, function () { if (_reactNative.Platform.OS === 'android') { // scrollview has a layout animation when create, must delay to call scrollTo after the animation _reactNative.InteractionManager.runAfterInteractions(function () { return _this.scrollviewRef && _this.scrollviewRef.scrollTo({ x: offsetX, y: offsetY, animated: false }); }); } }); }; _this.onChildLayout = function (e) { if (_this.props.vertical) { _this.setState({ height: e.nativeEvent.layout.height }); } }; var _this$props9 = _this.props, children = _this$props9.children, selectedIndex = _this$props9.selectedIndex; var count = _this.getChildrenCount(children); var index = count > 1 ? Math.min(selectedIndex, count - 1) : 0; _this.state = { width: 0, height: 0, isScrolling: false, autoplayEnd: false, loopJump: false, selectedIndex: index, offset: { x: 0, y: 0 } }; return _this; } (0, _createClass3['default'])(Carousel, [{ key: 'componentDidMount', value: function componentDidMount() { this.autoplay(); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { clearTimeout(this.autoplayTimer); clearTimeout(this.androidScrollEndTimer); clearTimeout(this.scrollEndTimter); } }, { key: 'render', value: function render() { var _this2 = this; var _state = this.state, width = _state.width, height = _state.height, selectedIndex = _state.selectedIndex; var _props = this.props, dots = _props.dots, infinite = _props.infinite, children = _props.children; if (!children) { return _react2['default'].createElement( _reactNative.Text, { style: { backgroundColor: 'white' } }, 'You are supposed to add children inside Carousel' ); } var pageStyle = { width: width }; var count = this.getChildrenCount(children); var pages = void 0; // For make infinite at least count > 1 if (count > 1) { // TODO: infinite var childrenArray = _react2['default'].Children.toArray(children); if (infinite) { childrenArray.unshift(childrenArray[count - 1]); childrenArray.push(childrenArray[1]); } pages = childrenArray.map(function (page, i) { return ( // when vertical, use the height of the first child as the height of the Carousel _react2['default'].createElement( _reactNative.View, { style: pageStyle, key: i, onLayout: i === 0 ? _this2.onChildLayout : function () {} }, page ) ); }); } else { pages = _react2['default'].createElement( _reactNative.View, { style: pageStyle, onLayout: this.onChildLayout }, children ); } return _react2['default'].createElement( _reactNative.View, { onLayout: this.onLayout, style: height > 0 ? { height: height } : {} }, this.renderContent(pages), dots && this.renderDots(selectedIndex) ); } }]); return Carousel; }(_react2['default'].Component); Carousel.defaultProps = { bounces: true, infinite: false, dots: true, autoplay: false, autoplayInterval: 3000, selectedIndex: 0, vertical: false, pagination: defaultPagination, dotStyle: {}, dotActiveStyle: {} }; exports['default'] = Carousel; module.exports = exports['default'];