如何使用Animated自动滚动列表(FlatList)?

时间:2017-06-10 15:44:44

标签: reactjs react-native react-native-flatlist

我有一个水平FlatList,每次到达结尾时,它会自动将新元素添加到列表中,因此它是一个无限列表。我希望应用程序自动滚动列表,而用户仍然可以来回滚动。这就是我的目标

export default class ImageCarousel extends Component {
  constructor(props) {
    super(props);

    this.scrollX = 0;
    this.offset = new Animated.Value(0);
    this.scrollTo = this.scrollTo.bind(this);
    this.handleScroll = this.handleScroll.bind(this);
    this.stopAnimation = this.stopAnimation.bind(this);
    // Listener to call the scrollToOffset function
    this.offset.addListener(this.scrollTo);
  }

  _scroller() {
    toValue = this.scrollX + 10; // Scroll 10 pixels in each loop
    this.animation = Animated.timing(
      this.offset,
      {
        toValue: toValue,
        duration: 1000, // A loop takes a second
        easing: Easing.linear,
      }
    );
    this.animation.start(() => this._scroller()); //Repeats itself when done
  }

  scrollTo(e) {
    this.carousel.scrollToOffset({offset: e.value});
  }

  handleScroll(event) {
    // Save the x (horizontal) value each time a scroll occurs
    this.scrollX = event.nativeEvent.contentOffset.x;
  }

  componentDidMount() {
    this._scroller();
  }
  render() {
    return (
      <View>
        <FlatList
          ref={el => this.carousel = el}
          data={someData}
          renderItem={renderFunction}
          horizontal={true}
          keyExtractor={someKeyFunction}
          onEndReached={loadMoreElementsFunction}
          onScroll={this.handleScroll}
        />
      </View>
    );
  }
}

它的工作原理是它会自动滚动列表,但问题是我无法手动滚动列表,因为scrollTo侦听器会不断更新滚动位置。我试图添加一个onPress回调以在按下FlatList时禁用动画,但是我无法让它工作。

2 个答案:

答案 0 :(得分:3)

  1. 这是我的数据。

Blockquote

state = { 
link: [
  'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
  'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
  'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
  'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
],};
  1. 定义FlatList引用
flatList = createRef();
  1. FlatList组件
   <FlatList
      style={{flex: 1}}
      data={this.state.link}
      keyExtractor={this._keyExtractor.bind(this)}
      renderItem={this._renderItem.bind(this)}
      horizontal={true}
      flatListRef={React.createRef()}
      ref={this.flatList}
    />
  1. 下一张幻灯片
  _goToNextPage = () => {
     if (CurrentSlide >= this.state.link.length-1) CurrentSlide = 0;
     this.flatList.current.scrollToIndex({
     index: ++CurrentSlide,
     animated: true,
    });
  };
  1. 开始和停止间隔
  _startAutoPlay = () => {
    this._timerId = setInterval(this._goToNextPage, IntervalTime);
  };



_stopAutoPlay = () => {
    if (this._timerId) {
      clearInterval(this._timerId);
      this._timerId = null;
    }
  };
  1. 关联功能
componentDidMount() {
   this._stopAutoPlay();
   this._startAutoPlay();
}

componentWillUnmount() {
   this._stopAutoPlay();
}

_renderItem({item, index}) {
    return <Image source={{uri: item}} style={styles.sliderItems} />;
 }

_keyExtractor(item, index) {
    return index.toString();
 }

完整代码:

import React, {Component, createRef} from 'react';
import {
  Text,
  View,
  ScrollView,
  Image,
  StyleSheet,
  Dimensions,
  FlatList,
} from 'react-native';

let CurrentSlide = 0;
let IntervalTime = 4000;

export default class Slider extends Component {
  flatList = createRef();

  // TODO _goToNextPage()
  _goToNextPage = () => {
    if (CurrentSlide >= this.state.link.length-1) CurrentSlide = 0;

    this.flatList.current.scrollToIndex({
      index: ++CurrentSlide,
      animated: true,
    });
  };

  _startAutoPlay = () => {
    this._timerId = setInterval(this._goToNextPage, IntervalTime);
  };

  _stopAutoPlay = () => {
    if (this._timerId) {
      clearInterval(this._timerId);
      this._timerId = null;
    }
  };


  componentDidMount() {
    this._stopAutoPlay();
    this._startAutoPlay();
  }

  componentWillUnmount() {
    this._stopAutoPlay();
  }

  // TODO _renderItem()
  _renderItem({item, index}) {
    return <Image source={{uri: item}} style={styles.sliderItems} />;
  }

  // TODO _keyExtractor()
  _keyExtractor(item, index) {
    // console.log(item);
    return index.toString();
  }
  state = {
    link: [
      'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
      'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
    //   'https://picsum.photos/200/300',
      'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
      'https://image.shutterstock.com/image-vector/online-exam-computer-web-app-260nw-1105800884.jpg',
    ],
  };

  render() {
    return (
      <View style={{marginTop: 10, marginBottom: 10}}>
        <FlatList
          style={{
            flex: 1,
            // TODO Remove extera global padding
            // marginLeft: -size.padding,
            // marginRight: -size.padding,
          }}
          data={this.state.link}
          keyExtractor={this._keyExtractor.bind(this)}
          renderItem={this._renderItem.bind(this)}
          horizontal={true}
          flatListRef={React.createRef()}
          ref={this.flatList}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  sliderItems: {
    marginLeft: 5,
    marginRight: 5,
    height: 200,
    width: Dimensions.get('window').width,
  },
});

答案 1 :(得分:0)

万一你还没有找到答案, 这是我使用FlatList创建自动滚动轮播的方法

import React, { Component } from 'react'
import {
  StyleSheet,
  View,
  FlatList,
  ScrollView,
  Dimensions,
  Image
} from 'react-native'

const { width } = Dimensions.get('window');
const height = width * 0.2844;

export default class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      search: '',
      sliderIndex: 0,
      maxSlider: 2,
      banners: [
        {_id: 1, imageUrl: 'https://www.do-cart.com/img/slider/1.jpg'},
        {_id: 2, imageUrl: 'https://www.do-cart.com/img/slider/2.jpg'},
        {_id: 3, imageUrl: 'https://www.do-cart.com/img/slider/3.jpg'},
      ],
    }
 }

 setRef = (c) => {
   this.listRef = c;
 }

 scrollToIndex = (index, animated) => {
   this.listRef && this.listRef.scrollToIndex({ index, animated })
 }

 componentWillMount() {
   setInterval(function() {
     const { sliderIndex, maxSlider } = this.state
     let nextIndex = 0

     if (sliderIndex < maxSlider) {
       nextIndex = sliderIndex + 1
     }

     this.scrollToIndex(nextIndex, true)
     this.setState({sliderIndex: nextIndex})
   }.bind(this), 3000)
 }

 render() {
   return (
     <View style={styles.container}>
       <View style={{height: 80, backgroundColor: '#123866', width:'100%'}}></View>

    <ScrollView style={styles.scrollContainer} showsVerticalScrollIndicator={false}>
      <FlatList
        ref={this.setRef}
        data={this.state.banners}
        horizontal
        showsHorizontalScrollIndicator={false}
        pagingEnabled
        keyExtractor={item => item._id}
        renderItem={({item, i}) => (
          <View key={i} style={{ height, width}}>
            <Image style={{ height, width }} source={{ uri: item.imageUrl }} />
          </View>
        )}
        onMomentumScrollEnd={(event) => {
          let sliderIndex = event.nativeEvent.contentOffset.x ? event.nativeEvent.contentOffset.x/width : 0
          this.setState({sliderIndex})
        }}
      />
      <View style={styles.sliderContainer}>
        {
          this.state.banners.map(function(item, index) {
            return (
              <View key={index} style={styles.sliderBtnContainer}>
                <View style={styles.sliderBtn}>
                  {
                    this.state.sliderIndex == index ? <View style={styles.sliderBtnSelected}/> : null
                  }
                </View>
              </View>
            )
          }.bind(this))
        }
      </View>
    </ScrollView>
  </View>
);
   }
 }

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  scrollContainer: {
    flex: 1
  },
  sliderContainer: {
    flexDirection: 'row',
    position: 'absolute',
    top: 80,
    alignSelf: 'center'
  },
  sliderBtn: {
    height: 13,
    width: 13,
    borderRadius: 12,
    borderWidth: 1,
    borderColor: 'white',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 10
  },
  sliderBtnSelected: {
    height: 12,
    width: 12,
    borderRadius: 6,
    backgroundColor: 'white',
  },
  sliderBtnContainer: {
    flexDirection: 'row', marginBottom: 24
  },
});

https://snack.expo.io/rJ9DOn0Ef