Authored by 鹿亮亮

提交自定义viewpager控件 review by 陈林

  1 +/**
  2 + * Description:
  3 + *
  4 + * Author: Bruce.Lu
  5 + * Version: 1.0
  6 + * Created on 2017/2/23.
  7 + */
  8 +import React from 'react';
  9 +import ReactNative from 'react-native';
  10 +
  11 +let {
  12 + requireNativeComponent,
  13 + View
  14 +} = ReactNative;
  15 +
  16 +let YH_PtrRefreshView = requireNativeComponent('YH_PtrRefresh', null);
  17 +
  18 +export default class YH_PtrRefresh extends React.Component {
  19 +
  20 + static propTypes = {
  21 + ...View.propTypes // 包含默认的View的属性
  22 + };
  23 +
  24 + constructor(props) {
  25 + super(props);
  26 + }
  27 +
  28 + render() {
  29 + return <YH_PtrRefreshView {...this.props} data={this.props.data} />;
  30 + }
  31 +}
  1 +/**
  2 + * Description:
  3 + *
  4 + * Author: Bruce.Lu
  5 + * Version: 1.0
  6 + * Created on 2017/2/23.
  7 + */
  8 +import React from 'react';
  9 +import ReactNative from 'react-native';
  10 +
  11 +let {
  12 + requireNativeComponent,
  13 + View,
  14 +} = ReactNative;
  15 +var dismissKeyboard = require('dismissKeyboard');
  16 +
  17 +let YH_ViewPagerView = requireNativeComponent('YH_ViewPager', null);
  18 +
  19 +var UIManager = require('UIManager');
  20 +
  21 +type Event = Object;
  22 +var VIEWPAGER_REF = 'viewPager';
  23 +
  24 +export type ViewPagerScrollState = $Enum<{
  25 + idle: string,
  26 + dragging: string,
  27 + settling: string,
  28 +}>;
  29 +
  30 +export default class YH_ViewPager extends React.Component {
  31 + props: {
  32 + initialPage?: number,
  33 + onPageScroll?: Function,
  34 + onPageScrollStateChanged?: Function,
  35 + onPageSelected?: Function,
  36 + pageMargin?: number,
  37 + keyboardDismissMode?: 'none' | 'on-drag',
  38 + scrollEnabled?: boolean,
  39 + };
  40 +
  41 + static propTypes = {
  42 + ...View.propTypes,
  43 + initialPage: React.PropTypes.number,
  44 + onPageScroll: React.PropTypes.func,
  45 + onPageScrollStateChanged: React.PropTypes.func,
  46 + onPageSelected: React.PropTypes.func,
  47 + pageMargin: React.PropTypes.number,
  48 + keyboardDismissMode: React.PropTypes.oneOf([
  49 + 'none', // default
  50 + 'on-drag',
  51 + ]),
  52 + scrollEnabled: React.PropTypes.bool,
  53 + };
  54 +
  55 + constructor(props) {
  56 + super(props);
  57 + }
  58 +
  59 + componentDidMount() {
  60 + if (this.props.initialPage != null) {
  61 + this.setPageWithoutAnimation(this.props.initialPage);
  62 + }
  63 + }
  64 +
  65 + _childrenWithOverridenStyle = (): Array => {
  66 + // Override styles so that each page will fill the parent. Native component
  67 + // will handle positioning of elements, so it's not important to offset
  68 + // them correctly.
  69 + return React.Children.map(this.props.children, function(child) {
  70 + if (!child) {
  71 + return null;
  72 + }
  73 + var newProps = {
  74 + ...child.props,
  75 + style: [child.props.style, {
  76 + position: 'absolute',
  77 + left: 0,
  78 + top: 0,
  79 + right: 0,
  80 + bottom: 0,
  81 + width: undefined,
  82 + height: undefined,
  83 + }],
  84 + collapsable: false,
  85 + };
  86 + if (child.type &&
  87 + child.type.displayName &&
  88 + (child.type.displayName !== 'RCTView') &&
  89 + (child.type.displayName !== 'View')) {
  90 + console.warn('Each ViewPager child must be a <View>. Was ' + child.type.displayName);
  91 + }
  92 + return React.createElement(child.type, newProps);
  93 + });
  94 + };
  95 +
  96 + _onPageScroll = (e: Event) => {
  97 + if (this.props.onPageScroll) {
  98 + this.props.onPageScroll(e);
  99 + }
  100 + if (this.props.keyboardDismissMode === 'on-drag') {
  101 + dismissKeyboard();
  102 + }
  103 + };
  104 +
  105 + _onPageScrollStateChanged = (e: Event) => {
  106 + if (this.props.onPageScrollStateChanged) {
  107 + this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
  108 + }
  109 + };
  110 +
  111 + _onPageSelected = (e: Event) => {
  112 + if (this.props.onPageSelected) {
  113 + this.props.onPageSelected(e);
  114 + }
  115 + };
  116 +
  117 + setPage = (selectedPage: number) => {
  118 + UIManager.dispatchViewManagerCommand(
  119 + ReactNative.findNodeHandle(this),
  120 + UIManager.AndroidViewPager.Commands.setPage,
  121 + [selectedPage],
  122 + );
  123 + };
  124 +
  125 + setPageWithoutAnimation = (selectedPage: number) => {
  126 + UIManager.dispatchViewManagerCommand(
  127 + ReactNative.findNodeHandle(this),
  128 + UIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
  129 + [selectedPage],
  130 + );
  131 + };
  132 +
  133 +
  134 + render() {
  135 + return (<YH_ViewPagerView
  136 + {...this.props}
  137 + ref={VIEWPAGER_REF}
  138 + style={this.props.style}
  139 + onPageScroll={this._onPageScroll}
  140 + onPageScrollStateChanged={this._onPageScrollStateChanged}
  141 + onPageSelected={this._onPageSelected}
  142 + children={this._childrenWithOverridenStyle()}
  143 + />);
  144 + }
  145 +}
  1 +import RecyclerSwiper from './src/'
  2 +module.exports = RecyclerSwiper
  1 +/**
  2 + * react-native-swiper
  3 + * @author leecade<leecade@163.com>
  4 + */
  5 +import React, { Component, PropTypes } from 'react'
  6 +import {
  7 + Text,
  8 + View,
  9 + ScrollView,
  10 + Dimensions,
  11 + TouchableOpacity,
  12 + ViewPagerAndroid,
  13 + Platform,
  14 + ActivityIndicator
  15 +} from 'react-native'
  16 +
  17 +import YH_ViewPager from '../../components/YH_ViewPager'
  18 +
  19 +const { width, height } = Dimensions.get('window')
  20 +
  21 +/**
  22 + * Default styles
  23 + * @type {StyleSheetPropType}
  24 + */
  25 +const styles = {
  26 + container: {
  27 + backgroundColor: 'transparent',
  28 + position: 'relative'
  29 + },
  30 +
  31 + wrapper: {
  32 + backgroundColor: 'transparent'
  33 + },
  34 +
  35 + slide: {
  36 + backgroundColor: 'transparent'
  37 + },
  38 +
  39 + pagination_x: {
  40 + position: 'absolute',
  41 + bottom: 25,
  42 + left: 0,
  43 + right: 0,
  44 + flexDirection: 'row',
  45 + flex: 1,
  46 + justifyContent: 'center',
  47 + alignItems: 'center',
  48 + backgroundColor: 'transparent'
  49 + },
  50 +
  51 + pagination_y: {
  52 + position: 'absolute',
  53 + right: 15,
  54 + top: 0,
  55 + bottom: 0,
  56 + flexDirection: 'column',
  57 + flex: 1,
  58 + justifyContent: 'center',
  59 + alignItems: 'center',
  60 + backgroundColor: 'transparent'
  61 + },
  62 +
  63 + title: {
  64 + height: 30,
  65 + justifyContent: 'center',
  66 + position: 'absolute',
  67 + paddingLeft: 10,
  68 + bottom: -30,
  69 + left: 0,
  70 + flexWrap: 'nowrap',
  71 + width: 250,
  72 + backgroundColor: 'transparent'
  73 + },
  74 +
  75 + buttonWrapper: {
  76 + backgroundColor: 'transparent',
  77 + flexDirection: 'row',
  78 + position: 'absolute',
  79 + top: 0,
  80 + left: 0,
  81 + flex: 1,
  82 + paddingHorizontal: 10,
  83 + paddingVertical: 10,
  84 + justifyContent: 'space-between',
  85 + alignItems: 'center'
  86 + },
  87 +
  88 + buttonText: {
  89 + fontSize: 50,
  90 + color: '#007aff',
  91 + fontFamily: 'Arial'
  92 + }
  93 +}
  94 +
  95 +// missing `module.exports = exports['default'];` with babel6
  96 +// export default React.createClass({
  97 +export default class extends Component {
  98 + /**
  99 + * Props Validation
  100 + * @type {Object}
  101 + */
  102 + static propTypes = {
  103 + horizontal: PropTypes.bool,
  104 + children: PropTypes.node.isRequired,
  105 + style: View.propTypes.style,
  106 + pagingEnabled: PropTypes.bool,
  107 + showsHorizontalScrollIndicator: PropTypes.bool,
  108 + showsVerticalScrollIndicator: PropTypes.bool,
  109 + bounces: PropTypes.bool,
  110 + scrollsToTop: PropTypes.bool,
  111 + removeClippedSubviews: PropTypes.bool,
  112 + automaticallyAdjustContentInsets: PropTypes.bool,
  113 + showsPagination: PropTypes.bool,
  114 + showsButtons: PropTypes.bool,
  115 + loadMinimal: PropTypes.bool,
  116 + loadMinimalSize: PropTypes.number,
  117 + loadMinimalLoader: PropTypes.element,
  118 + loop: PropTypes.bool,
  119 + autoplay: PropTypes.bool,
  120 + autoplayTimeout: PropTypes.number,
  121 + autoplayDirection: PropTypes.bool,
  122 + index: PropTypes.number,
  123 + renderPagination: PropTypes.func,
  124 + dotStyle: PropTypes.object,
  125 + activeDotStyle: PropTypes.object,
  126 + dotColor: PropTypes.string,
  127 + activeDotColor: PropTypes.string
  128 + }
  129 +
  130 + /**
  131 + * Default props
  132 + * @return {object} props
  133 + * @see http://facebook.github.io/react-native/docs/scrollview.html
  134 + */
  135 + static defaultProps = {
  136 + horizontal: true,
  137 + pagingEnabled: true,
  138 + showsHorizontalScrollIndicator: false,
  139 + showsVerticalScrollIndicator: false,
  140 + bounces: false,
  141 + scrollsToTop: false,
  142 + removeClippedSubviews: true,
  143 + automaticallyAdjustContentInsets: false,
  144 + showsPagination: true,
  145 + showsButtons: false,
  146 + loop: true,
  147 + loadMinimal: false,
  148 + loadMinimalSize: 1,
  149 + autoplay: false,
  150 + autoplayTimeout: 2.5,
  151 + autoplayDirection: true,
  152 + index: 0
  153 + }
  154 +
  155 + /**
  156 + * Init states
  157 + * @return {object} states
  158 + */
  159 + state = this.initState(this.props, true)
  160 +
  161 + /**
  162 + * autoplay timer
  163 + * @type {null}
  164 + */
  165 + autoplayTimer = null
  166 + loopJumpTimer = null
  167 +
  168 + componentWillReceiveProps (nextProps) {
  169 + const sizeChanged = (nextProps.width || width) !== this.state.width ||
  170 + (nextProps.height || height) !== this.state.height
  171 + if (!nextProps.autoplay && this.autoplayTimer) clearTimeout(this.autoplayTimer)
  172 + this.setState(this.initState(nextProps, sizeChanged))
  173 + }
  174 +
  175 + componentDidMount () {
  176 + this.autoplay()
  177 + }
  178 +
  179 + componentWillUnmount () {
  180 + this.autoplayTimer && clearTimeout(this.autoplayTimer)
  181 + this.loopJumpTimer && clearTimeout(this.loopJumpTimer)
  182 + }
  183 +
  184 + initState (props, setOffsetInState) {
  185 + // set the current state
  186 + const state = this.state || {}
  187 +
  188 + const initState = {
  189 + autoplayEnd: false,
  190 + loopJump: false
  191 + }
  192 +
  193 + const newInternals = {
  194 + isScrolling: false
  195 + }
  196 +
  197 + initState.total = props.children ? props.children.length || 1 : 0
  198 + if (state.total === initState.total) {
  199 + // retain the index
  200 + initState.index = state.index
  201 + } else {
  202 + // reset the index
  203 + setOffsetInState = true // if the index is reset, go ahead and update the offset in state
  204 + initState.index = initState.total > 1 ? Math.min(props.index, initState.total - 1) : 0
  205 + }
  206 +
  207 + // Default: horizontal
  208 + initState.dir = props.horizontal === false ? 'y' : 'x'
  209 + initState.width = props.width || width
  210 + initState.height = props.height || height
  211 + newInternals.offset = {}
  212 +
  213 + if (initState.total > 1) {
  214 + let setup = initState.index
  215 + if (props.loop) {
  216 + setup++
  217 + }
  218 + newInternals.offset[initState.dir] = initState.dir === 'y'
  219 + ? initState.height * setup
  220 + : initState.width * setup
  221 + }
  222 +
  223 + // only update the offset in state if needed, updating offset while swiping
  224 + // causes some bad jumping / stuttering
  225 + if (setOffsetInState) {
  226 + initState.offset = newInternals.offset
  227 + }
  228 +
  229 + this.internals = newInternals
  230 + return initState
  231 + }
  232 +
  233 + // include internals with state
  234 + fullState () {
  235 + return Object.assign({}, this.state, this.internals)
  236 + }
  237 +
  238 + loopJump = () => {
  239 + if (!this.state.loopJump) return
  240 + const i = this.state.index + (this.props.loop ? 1 : 0)
  241 + const scrollView = this.refs.scrollView
  242 + this.loopJumpTimer = setTimeout(() => scrollView.setPageWithoutAnimation &&
  243 + scrollView.setPageWithoutAnimation(i), 50)
  244 + }
  245 +
  246 + /**
  247 + * Automatic rolling
  248 + */
  249 + autoplay = () => {
  250 + if (!Array.isArray(this.props.children) ||
  251 + !this.props.autoplay ||
  252 + this.internals.isScrolling ||
  253 + this.state.autoplayEnd) return
  254 +
  255 + this.autoplayTimer && clearTimeout(this.autoplayTimer)
  256 + this.autoplayTimer = setTimeout(() => {
  257 + if (!this.props.loop && (
  258 + this.props.autoplayDirection
  259 + ? this.state.index === this.state.total - 1
  260 + : this.state.index === 0
  261 + )
  262 + ) return this.setState({ autoplayEnd: true })
  263 +
  264 + this.scrollBy(this.props.autoplayDirection ? 1 : -1)
  265 + }, this.props.autoplayTimeout * 1000)
  266 + }
  267 +
  268 + /**
  269 + * Scroll begin handle
  270 + * @param {object} e native event
  271 + */
  272 + onScrollBegin = e => {
  273 + // update scroll state
  274 + this.internals.isScrolling = true
  275 + this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e, this.fullState(), this)
  276 + }
  277 +
  278 + /**
  279 + * Scroll end handle
  280 + * @param {object} e native event
  281 + */
  282 + onScrollEnd = e => {
  283 + console.log('onPageSelected');
  284 + // update scroll state
  285 + this.internals.isScrolling = false
  286 +
  287 + // making our events coming from android compatible to updateIndex logic
  288 + if (!e.nativeEvent.contentOffset) {
  289 + if (this.state.dir === 'x') {
  290 + e.nativeEvent.contentOffset = {x: e.nativeEvent.position * this.state.width}
  291 + } else {
  292 + e.nativeEvent.contentOffset = {y: e.nativeEvent.position * this.state.height}
  293 + }
  294 + }
  295 +
  296 + this.updateIndex(e.nativeEvent.contentOffset, this.state.dir, () => {
  297 + this.autoplay()
  298 + this.loopJump()
  299 +
  300 + // if `onMomentumScrollEnd` registered will be called here
  301 + this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e, this.fullState(), this)
  302 + })
  303 + }
  304 +
  305 + /*
  306 + * Drag end handle
  307 + * @param {object} e native event
  308 + */
  309 + onScrollEndDrag = e => {
  310 + const { contentOffset } = e.nativeEvent
  311 + const { horizontal, children } = this.props
  312 + const { index } = this.state
  313 + const { offset } = this.internals
  314 + const previousOffset = horizontal ? offset.x : offset.y
  315 + const newOffset = horizontal ? contentOffset.x : contentOffset.y
  316 +
  317 + if (previousOffset === newOffset &&
  318 + (index === 0 || index === children.length - 1)) {
  319 + this.internals.isScrolling = false
  320 + }
  321 + }
  322 +
  323 + /**
  324 + * Update index after scroll
  325 + * @param {object} offset content offset
  326 + * @param {string} dir 'x' || 'y'
  327 + */
  328 + updateIndex = (offset, dir, cb) => {
  329 + const state = this.state
  330 + let index = state.index
  331 + const diff = offset[dir] - this.internals.offset[dir]
  332 + const step = dir === 'x' ? state.width : state.height
  333 + let loopJump = false
  334 +
  335 + // Do nothing if offset no change.
  336 + if (!diff) return
  337 +
  338 + // Note: if touch very very quickly and continuous,
  339 + // the variation of `index` more than 1.
  340 + // parseInt() ensures it's always an integer
  341 + index = parseInt(index + Math.round(diff / step))
  342 +
  343 + if (this.props.loop) {
  344 + if (index <= -1) {
  345 + index = state.total - 1
  346 + offset[dir] = step * state.total
  347 + loopJump = true
  348 + } else if (index >= state.total) {
  349 + index = 0
  350 + offset[dir] = step
  351 + loopJump = true
  352 + }
  353 + }
  354 +
  355 + const newState = {}
  356 + newState.index = index
  357 + newState.loopJump = loopJump
  358 +
  359 + this.internals.offset = offset
  360 +
  361 + // only update offset in state if loopJump is true
  362 + if (loopJump) {
  363 + // when swiping to the beginning of a looping set for the third time,
  364 + // the new offset will be the same as the last one set in state.
  365 + // Setting the offset to the same thing will not do anything,
  366 + // so we increment it by 1 then immediately set it to what it should be,
  367 + // after render.
  368 + if (offset[dir] === this.state.offset[dir]) {
  369 + newState.offset = { x: 0, y: 0 }
  370 + newState.offset[dir] = offset[dir] + 1
  371 + this.setState(newState, () => {
  372 + this.setState({ offset: offset }, cb)
  373 + })
  374 + } else {
  375 + newState.offset = offset
  376 + this.setState(newState, cb)
  377 + }
  378 + } else {
  379 + this.setState(newState, cb)
  380 + }
  381 + }
  382 +
  383 + /**
  384 + * Scroll by index
  385 + * @param {number} index offset index
  386 + * @param {bool} animated
  387 + */
  388 +
  389 + scrollBy = (index, animated = true) => {
  390 + if (this.internals.isScrolling || this.state.total < 2) return
  391 + const state = this.state
  392 + const diff = (this.props.loop ? 1 : 0) + index + this.state.index
  393 + let x = 0
  394 + let y = 0
  395 + if (state.dir === 'x') x = diff * state.width
  396 + if (state.dir === 'y') y = diff * state.height
  397 +
  398 + console.log('xxxxx scrollBy diff=' + diff);
  399 + if (Platform.OS === 'android') {
  400 + this.refs.scrollView && this.refs.scrollView[animated ? 'setPage' : 'setPageWithoutAnimation'](diff)
  401 + } else {
  402 + this.refs.scrollView && this.refs.scrollView.scrollTo({ x, y, animated })
  403 + }
  404 +
  405 + // update scroll state
  406 + this.internals.isScrolling = true
  407 + this.setState({
  408 + autoplayEnd: false
  409 + })
  410 +
  411 + // trigger onScrollEnd manually in android
  412 + if (!animated || Platform.OS === 'android') {
  413 + setImmediate(() => {
  414 + this.onScrollEnd({
  415 + nativeEvent: {
  416 + position: diff
  417 + }
  418 + })
  419 + })
  420 + }
  421 + }
  422 +
  423 + scrollViewPropOverrides = () => {
  424 + const props = this.props
  425 + let overrides = {}
  426 +
  427 + /*
  428 + const scrollResponders = [
  429 + 'onMomentumScrollBegin',
  430 + 'onTouchStartCapture',
  431 + 'onTouchStart',
  432 + 'onTouchEnd',
  433 + 'onResponderRelease',
  434 + ]
  435 + */
  436 +
  437 + for (let prop in props) {
  438 + // if(~scrollResponders.indexOf(prop)
  439 + if (typeof props[prop] === 'function' &&
  440 + prop !== 'onMomentumScrollEnd' &&
  441 + prop !== 'renderPagination' &&
  442 + prop !== 'onScrollBeginDrag'
  443 + ) {
  444 + let originResponder = props[prop]
  445 + overrides[prop] = (e) => originResponder(e, this.fullState(), this)
  446 + }
  447 + }
  448 +
  449 + return overrides
  450 + }
  451 +
  452 + /**
  453 + * Render pagination
  454 + * @return {object} react-dom
  455 + */
  456 + renderPagination = () => {
  457 + // By default, dots only show when `total` >= 2
  458 + if (this.state.total <= 1) return null
  459 +
  460 + let dots = []
  461 + const ActiveDot = this.props.activeDot || <View style={[{
  462 + backgroundColor: this.props.activeDotColor || '#007aff',
  463 + width: 8,
  464 + height: 8,
  465 + borderRadius: 4,
  466 + marginLeft: 3,
  467 + marginRight: 3,
  468 + marginTop: 3,
  469 + marginBottom: 3
  470 + }, this.props.activeDotStyle]} />
  471 + const Dot = this.props.dot || <View style={[{
  472 + backgroundColor: this.props.dotColor || 'rgba(0,0,0,.2)',
  473 + width: 8,
  474 + height: 8,
  475 + borderRadius: 4,
  476 + marginLeft: 3,
  477 + marginRight: 3,
  478 + marginTop: 3,
  479 + marginBottom: 3
  480 + }, this.props.dotStyle ]} />
  481 + for (let i = 0; i < this.state.total; i++) {
  482 + dots.push(i === this.state.index
  483 + ? React.cloneElement(ActiveDot, {key: i})
  484 + : React.cloneElement(Dot, {key: i})
  485 + )
  486 + }
  487 +
  488 + return (
  489 + <View pointerEvents='none' style={[styles['pagination_' + this.state.dir], this.props.paginationStyle]}>
  490 + {dots}
  491 + </View>
  492 + )
  493 + }
  494 +
  495 + renderTitle = () => {
  496 + const child = this.props.children[this.state.index]
  497 + const title = child && child.props && child.props.title
  498 + return title
  499 + ? (<View style={styles.title}>
  500 + {this.props.children[this.state.index].props.title}
  501 + </View>)
  502 + : null
  503 + }
  504 +
  505 + renderNextButton = () => {
  506 + let button = null
  507 +
  508 + if (this.props.loop ||
  509 + this.state.index !== this.state.total - 1) {
  510 + button = this.props.nextButton || <Text style={styles.buttonText}></Text>
  511 + }
  512 +
  513 + return (
  514 + <TouchableOpacity onPress={() => button !== null && this.scrollBy(1)}>
  515 + <View>
  516 + {button}
  517 + </View>
  518 + </TouchableOpacity>
  519 + )
  520 + }
  521 +
  522 + renderPrevButton = () => {
  523 + let button = null
  524 +
  525 + if (this.props.loop || this.state.index !== 0) {
  526 + button = this.props.prevButton || <Text style={styles.buttonText}></Text>
  527 + }
  528 +
  529 + return (
  530 + <TouchableOpacity onPress={() => button !== null && this.scrollBy(-1)}>
  531 + <View>
  532 + {button}
  533 + </View>
  534 + </TouchableOpacity>
  535 + )
  536 + }
  537 +
  538 + renderButtons = () => {
  539 + return (
  540 + <View pointerEvents='box-none' style={[styles.buttonWrapper, {
  541 + width: this.state.width,
  542 + height: this.state.height
  543 + }, this.props.buttonWrapperStyle]}>
  544 + {this.renderPrevButton()}
  545 + {this.renderNextButton()}
  546 + </View>
  547 + )
  548 + }
  549 +
  550 + renderScrollView = pages => {
  551 + if (Platform.OS === 'ios') {
  552 + return (
  553 + <ScrollView ref='scrollView'
  554 + {...this.props}
  555 + {...this.scrollViewPropOverrides()}
  556 + contentContainerStyle={[styles.wrapper, this.props.style]}
  557 + contentOffset={this.state.offset}
  558 + onScrollBeginDrag={this.onScrollBegin}
  559 + onMomentumScrollEnd={this.onScrollEnd}
  560 + onScrollEndDrag={this.onScrollEndDrag}>
  561 + {pages}
  562 + </ScrollView>
  563 + )
  564 + }
  565 + return (
  566 + <YH_ViewPager ref='scrollView'
  567 + {...this.props}
  568 + initialPage={this.props.loop ? this.state.index + 1 : this.state.index}
  569 + onPageSelected={this.onScrollEnd}
  570 + style={{flex: 1}}>
  571 + {pages}
  572 + </YH_ViewPager>
  573 + )
  574 + }
  575 +
  576 + /**
  577 + * Default render
  578 + * @return {object} react-dom
  579 + */
  580 + render () {
  581 + const state = this.state
  582 + const props = this.props
  583 + const children = props.children
  584 + const index = state.index
  585 + const total = state.total
  586 + const loop = props.loop
  587 + // let dir = state.dir
  588 + // let key = 0
  589 + const loopVal = loop ? 1 : 0
  590 +
  591 + let pages = []
  592 +
  593 + const pageStyle = [{width: state.width, height: state.height}, styles.slide]
  594 + const pageStyleLoading = {
  595 + width: this.state.width,
  596 + height: this.state.height,
  597 + justifyContent: 'center',
  598 + alignItems: 'center'
  599 + }
  600 +
  601 + // For make infinite at least total > 1
  602 + if (total > 1) {
  603 + // Re-design a loop model for avoid img flickering
  604 + pages = Object.keys(children)
  605 + if (loop) {
  606 + pages.unshift(total - 1 + '')
  607 + pages.push('0')
  608 + }
  609 + console.log(pages);
  610 +
  611 + pages = pages.map((page, i) => {
  612 + if (props.loadMinimal) {
  613 + if (i >= (index + loopVal - props.loadMinimalSize) &&
  614 + i <= (index + loopVal + props.loadMinimalSize)) {
  615 + return <View style={pageStyle} key={i}>{children[page]}</View>
  616 + } else {
  617 + return (
  618 + <View style={pageStyleLoading} key={`loading-${i}`}>
  619 + {props.loadMinimalLoader ? props.loadMinimalLoader : <ActivityIndicator />}
  620 + </View>
  621 + )
  622 + }
  623 + } else {
  624 + return <View style={pageStyle} key={i}>{children[page]}</View>
  625 + }
  626 + })
  627 + } else {
  628 + pages = <View style={pageStyle} key={0}>{children}</View>
  629 + }
  630 +
  631 + return (
  632 + <View style={[styles.container, {
  633 + width: state.width,
  634 + height: state.height
  635 + }]}>
  636 + {this.renderScrollView(pages)}
  637 + {props.showsPagination && (props.renderPagination
  638 + ? this.props.renderPagination(state.index, state.total, this)
  639 + : this.renderPagination())}
  640 + {this.renderTitle()}
  641 + {this.props.showsButtons && this.renderButtons()}
  642 + </View>
  643 + )
  644 + }
  645 +}
@@ -54,7 +54,7 @@ function calcluateFloorHeight(payload) { @@ -54,7 +54,7 @@ function calcluateFloorHeight(payload) {
54 let padding = count == 4 ? padding4 : padding5; 54 let padding = count == 4 ? padding4 : padding5;
55 floorHeight = (count == 4 ? 84 : 75) * lineNumber + padding * (lineNumber - 1) + 12; 55 floorHeight = (count == 4 ? 84 : 75) * lineNumber + padding * (lineNumber - 1) + 12;
56 break; 56 break;
57 - } 57 + }
58 case 'app_hot_brands': { 58 case 'app_hot_brands': {
59 let listLength = data.list.length; 59 let listLength = data.list.length;
60 let lineNumber = parseInt((listLength + 3) / 4); 60 let lineNumber = parseInt((listLength + 3) / 4);
@@ -171,7 +171,7 @@ function calcluateFloorHeight(payload) { @@ -171,7 +171,7 @@ function calcluateFloorHeight(payload) {
171 let leftBigImageWidth = width * 310 / 740; 171 let leftBigImageWidth = width * 310 / 740;
172 let leftBigImageHeight = leftBigImageWidth * 422 / 310; 172 let leftBigImageHeight = leftBigImageWidth * 422 / 310;
173 let containerHeight = headerHeight + leftBigImageHeight; 173 let containerHeight = headerHeight + leftBigImageHeight;
174 - if(item.big_image.length > 0){ 174 + if(data.big_image.length > 0){
175 containerHeight = containerHeight + bannerHeight; 175 containerHeight = containerHeight + bannerHeight;
176 } 176 }
177 floorHeight = containerHeight; 177 floorHeight = containerHeight;
@@ -210,7 +210,7 @@ function calcluateFloorHeight(payload) { @@ -210,7 +210,7 @@ function calcluateFloorHeight(payload) {
210 let imageWidth = cellWidth - 14 * 2; 210 let imageWidth = cellWidth - 14 * 2;
211 let imageHeight = imageWidth * 168 / 126; 211 let imageHeight = imageWidth * 168 / 126;
212 let cellHeight = imageHeight + 20; 212 let cellHeight = imageHeight + 20;
213 - let lineNumber = parseInt((item.list.length + 3) / 4); 213 + let lineNumber = parseInt((data.list.length + 3) / 4);
214 let listHeight = Math.floor(lineNumber * cellHeight); 214 let listHeight = Math.floor(lineNumber * cellHeight);
215 let containerHeight = listHeight + headerHeight; 215 let containerHeight = listHeight + headerHeight;
216 floorHeight = containerHeight; 216 floorHeight = containerHeight;