React Native: Correct scrolling in horizontal FlatList with Item Separator

Yury picture Yury · Feb 4, 2018 · Viewed 22.5k times · Source

ReactNative: v0.52.0

Platform: iOS

My FlatList code:

<FlatList
  horizontal
  pagingEnabled={true}
  showsHorizontalScrollIndicator={false}

  legacyImplementation={false}

  data={this.props.photos}
  renderItem={item => this.renderPhoto(item)}
  keyExtractor={photo => photo.id}

  ItemSeparatorComponent={this.itemSeparatorComponent}
/>

Item separator code:

itemSeparatorComponent = () => {
    return <View style = {
        {
            height: '100%',
            width: 5,
            backgroundColor: 'red',
        }
    }
    />
}

And finally FlatList item component:

renderPhoto = ({ item, index }) => {
    return (
        <View style = {{ width: SCREEN_WIDTH, height: 'auto' }}>
          <FastImage 
            style = { styles.photo }
            resizeMode = { FastImage.resizeMode.contain }
            source = {{ uri: item.source.uri }}
          /> 
        </View>
    )
}

But when scrolling, the FlatList makes an offset to the separator but not to the left edge of item:

enter image description here

And with each new element the FlatList adds the width of the all previous separators to offset:

enter image description here

How to make the FlatList component consider the width of the separator component in horizontal scrolling and make proper offset?

Answer

Yash Gadle picture Yash Gadle · Nov 8, 2018

I had the same use-case. For anyone looking for a solution, here it is.

Step 1) Don't use ItemSeparatorComponent prop. Instead, render it inline in your renderItem component.

Step 2) (Key-point). Specify the width and height in the style prop of the FlatList. The width, in your case, should be SCREEN_WIDTH + 5.

Then Flatlist will automatically move the entire screen (photo + separator) away when pagination is enabled. So now your code should be like so:-

<FlatList
  horizontal
  pagingEnabled={true}
  showsHorizontalScrollIndicator={false}
  legacyImplementation={false}
  data={this.props.photos}
  renderItem={item => this.renderPhoto(item)}
  keyExtractor={photo => photo.id}
  style={{width: SCREEN_WIDTH + 5, height:'100%'}}
/>

Render photo code:-

renderPhoto = ({ item, index }) => {
return (
    <View style = {{ width: SCREEN_WIDTH + 5, height: 'auto', 
      flexDirection:'row'}}>
      <FastImage 
        style = { styles.photo }
        resizeMode = { FastImage.resizeMode.contain }
        source = {{ uri: item.source.uri }}
      /> 
      {this. itemSeparatorComponent()}
    </View>
)}

Item separator code:

itemSeparatorComponent = () => {
return <View style = {
    {
        height: '100%',
        width: 5,
        backgroundColor: 'red',
    }
}
/>
}

If you still can't figure it out, then look at this component:
https://github.com/zachgibson/react-native-parallax-swiper

Try to go into the implementation, you will see that this guy has provided width and height to the Animated.ScrollView.
https://github.com/zachgibson/react-native-parallax-swiper/blob/master/src/ParallaxSwiper.js
Line number: 93 - 97