React Native: Correct scrolling in horizontal FlatList with Item Separator
Asked Answered
B

2

15

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?

Backboard answered 4/2, 2018 at 15:36 Comment(0)
W
12

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

Wo answered 8/11, 2018 at 13:7 Comment(0)
E
2

The top-level view you're returning in the renderPhoto function has a width of SCREEN_WIDTH, yet the ItemSeparatorComponent, which renders in between each item, is taking up a width of 5 as per your style definition. Consequently, for each additional item you scroll to, that initial offset will become 5 more pixels on the left.

To fix this, you can either remove the ItemSeparatorComponent completely, (as you already have pagingEnabled set to true), or set the width of the top-level view returned in renderPhoto equal to SCREEN_WIDTH - 2.5. That way you'll see half of the item separator on the right edge of one photo and the other half on the left edge of the next photo.

Actually, one other possible solution could be to remove the item separator, set the renderPhoto View's width to SCREEN_WIDTH + 5, and then include these additional properties inside the style: {paddingRight: 5, borderRightWidth: 5, borderRightColor: 'red'}. That way the red separator won't be visible until scrolling left and right, because of the pagingEnabled property.

Efrenefron answered 7/2, 2018 at 13:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.