react-native ViewPagerAndroid 坑1

ViewPagerAndroid组件 在更新新的data时 页面显示空

解决办法 在data发生变化时 传入新的data的长度

<ViewPagerAndroid

key={this.props.children.length}

style={{ flex: 1 }}

onPageScroll={this.onPageScroll}

onScrollBeginDrag={this._onScrollBegin}

scrollEnabled={this.props.scrollEnabled}

onPageScrollStateChanged={this.onPageScrollStateChanged}

onPageSelected={this.onPageSelected}

ref={viewPager => { this.viewPager = viewPager; }}

initialPage={this.props.initialPage}>

{this._children().map((child, index) => {

return child;

})}

</ViewPagerAndroid>

import React, { Component } from 'react'

import {
  View,
  FlatList,
  Animated,
  DeviceEventEmitter,
  ViewPagerAndroid
} from 'react-native';
import PropTypes from 'prop-types';
import { Width, isAndroid } from '../../global/rn.base';

const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);



class ScrollTabView extends Component {
  static defaultProps = {
    horizontal: true,
    scrollEventThrottle: 16,
    scrollEnabled: true,
    pagingEnabled: true,
    showsHorizontalScrollIndicator: false,
    showsVerticalScrollIndicator: false,
    snapToAlignment: 'center',
    initialPage: 0,
    onScrollBegin: () => { },
    navPosition: 'top',
    onChangeTab: () => { }
  };
  constructor(props) {
    super(props);
    this.state = {
      viewWidth: Width,
      refresh:true
    };
    if (props.jumpToView && typeof props.jumpToView === 'function') props.jumpToView(this._goToPage);
    this.scrollViewProps = {
      style: this.props.style,
      currentPage: this.props.initialPage,
      initialScrollIndex: this.props.initialPage,
      horizontal: this.props.horizontal,
      alwaysBounceHorizontal: this.props.alwaysBounceHorizontal,
      bounces: this.props.bounces,
      scrollEventThrottle: this.props.scrollEventThrottle,
      pagingEnabled: this.props.pagingEnabled,
      snapToAlignment: this.props.snapToAlignment,
      showsHorizontalScrollIndicator: this.props.showsHorizontalScrollIndicator,
      showsVerticalScrollIndicator: this.props.showsVerticalScrollIndicator
    };
  }

  _refresh = (fn) => {
    this.setState({refresh: !this.state.refresh},()=>{if(fn)fn()})
  }

  componentWillReceiveProps() {
    this.setState({refresh: !this.state.refresh})
    console.log(111)
  }

  componentWillMount() {

  }

  componentDidUpdate() {
  }

  componentDidMount() {
  }

  _children(children = this.props.children) {
    return React.Children.map(children, (child) => child);
  }

  _renderTabBar(props) {
    if (this.props.renderTabBar === false) {
      return null;
    } else if (this.props.renderTabBar) {
      return React.cloneElement(this.props.renderTabBar(props), props);
    } else {
      return null;
    }
  }

  _renderScrollableContent = ({ item, index }) => {
    return <View key={item.props.tabName + '_' + index} style={{ width: this.state.viewWidth }}>
      {item}
    </View>
  };
  _resetScroll = (num, force = false) => {
    if (isAndroid) this.viewPager.setPageWithoutAnimation(num);
    let lastNum = this.scrollViewProps.currentPage;
    this._navBar._resetCurrentPage(num);
    if (num !== lastNum) {
      if (isAndroid) {
        this.viewPager.setPageWithoutAnimation(num);
        this._dealOffsetParam(num, true);
        if (this.props.onChangeTab) this.props.onChangeTab({ i: num });
      } else {
        this._scroll.getNode().scrollToIndex({ index: Number(num) });
      }
      this._navBar._resetUnderLine(num);
    }
  };

  _movingEnd = (event) => {
    const { x } = event.nativeEvent.contentOffset;
    let page = parseInt(x / this.state.viewWidth);
    this.scrollViewProps.currentPage = page;
    this._dealOffsetParam(x, true);
    this.props.onChangeTab({ i: page });
  };
  _listingScroll = (event) => {
    const { x } = event.nativeEvent.contentOffset;
    this._dealOffsetParam(x, false);
  };
  _dealOffsetParam(x, isEnd) {
    if (this._navBar && typeof this._navBar.listenScroll === 'function') this._navBar.listenScroll({
      value: isAndroid ? x : (x / this.state.viewWidth),
      isEnd: isEnd
    });
  }
  _goToPage = (num, option = {}) => {
    let { isInit = false, animated = true } = option;
    let lastNum = this.scrollViewProps.currentPage;
    this.scrollViewProps.currentPage = num;
    this._navBar._resetCurrentPage(num);
    this._onScrollBegin();
    if (!isInit) {
      if (isAndroid) {
        if (animated) this.viewPager.setPage(num);
        else this.viewPager.setPageWithoutAnimation(num);
      } else {
        this._scroll.getNode().scrollToIndex({ index: Number(num), animated });
      }
      this.props.onChangeTab({ i: num });
      if (this.props.onTabClick) this.props.onTabClick(lastNum, num);
    }
  };
  onPageScroll = ({ nativeEvent }) => {
    const { offset, position } = nativeEvent;
    this.scrollViewProps.currentPage = position;
    this._dealOffsetParam(offset + position, false);
  };
  onPageScrollStateChanged = (type) => {
    if (type === 'idle') {
      let position = this.scrollViewProps.currentPage;
      this._dealOffsetParam(position, true);
      this.props.onChangeTab({ i: position })
    }
  };
  _onScrollBegin = () => {
    this.props.onScrollBegin && this.props.onScrollBegin(this.scrollViewProps.currentPage);
  };
  render() {
    let tabBarProps = {
      tabs: this._children().map((child) => {
        return {
          name: child.props.tabName,
          number: child.props.tabNumber
        }
      }),
      ref: (scroll) => {
        this._navBar = scroll
      },
      goToPage: this._goToPage,
      initialPage: this.scrollViewProps.currentPage,
      scrollEventThrottle: this.props.scrollEventThrottle,
    };
    return (
      <View style={this.props.height ? { height: this.props.height } : { flex: 1 }}>
        {this.props.navPosition === 'top' ? this._renderTabBar(tabBarProps) : null}
        {isAndroid ?
          <ViewPagerAndroid
            key={this.props.children.length}
            style={{ flex: 1 }}
            onPageScroll={this.onPageScroll}
            onScrollBeginDrag={this._onScrollBegin}
            scrollEnabled={this.props.scrollEnabled}
            onPageScrollStateChanged={this.onPageScrollStateChanged}
            onPageSelected={this.onPageSelected}
            ref={viewPager => { this.viewPager = viewPager; }}
            initialPage={this.props.initialPage}>
            {this._children().map((child, index) => {
              return child;
            })}
          </ViewPagerAndroid>
          : <AnimatedFlatList
            {...this.scrollViewProps}
            ref={(scroll) => {
              this._scroll = scroll
            }}
            data={this._children()}
            scrollEnabled={this.props.scrollEnabled}
            getItemLayout={(data, index) => ({ length: Width, offset: Width * index, index })}
            renderItem={this._renderScrollableContent}
            onMomentumScrollEnd={this._movingEnd}//android
            onScrollBeginDrag={this._onScrollBegin}
            onScrollAnimationEnd={this._movingEnd}//ios
            onScroll={this._listingScroll}
          />
        }
        {this.props.navPosition === 'bottom' ? this._renderTabBar(tabBarProps) : null}
      </View>
    )
  }
}

ScrollTabView.propTypes = {
  onChangeTab: PropTypes.func,
  onTabClick: PropTypes.func,
  initialPage: PropTypes.number
};
export default ScrollTabView;