Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to scroll to certain index in FlatList with variable item size

Tags:

react-native

I'm having a trouble adding scroll/jump to certain index functionality on FlatList in react-native. My FlatList items are vary in size (height) which makes me unable to implement getItemLayout since this requires me to have prior knowledge about the FlatList item size, therefore I cannot use scrollToIndex (which requires getItemLayout to be implemented).

My solution was to get each item's size when rendered by using onLayout and map them with their index. I can then use each item size to get their offset and use scrollToOffset to jump to the given item (by using scrollToItem function in the code below). The issue here is that I am not able to jump to certain item until that item has been rendered. My temporary solution for that is by tweaking initialNumberToRender close to the number of data and set the windowSize props as high as possible so that all of the items will be rendered (even though the user doesn't scroll down).

getOffsetByIndex = (index) => {
    let offset = 0;
    for (let i = 0; i < index; i++) {
      const elementLayout = this.layoutMap[index];
      if (elementLayout && elementLayout.height) {
        offset += this.layoutMap[i].height;
      }
    }
    return offset;
};

scrollToItem = (index) => {
  const offset = this.getOffsetByIndex(index);
  this.flatListRef.scrollToOffset(offset);
};

addToLayoutMap = (layout, index) => {
  this.layoutMap[index] = layout;
};

render(){
  return(
    <FlatList
      ref={this.flatListRef}
      data={this.state.data}
      renderItem={() => <View onLayout={this.addToLayoutMap}> <SomeComponent/> </View>}
      initialNumToRender={this.state.data.length / 5}
      windowSize={this.state.data.length}
    />
  );
}

This solution works with small number of data, but when the data is large (containing ~300 of rows), it will take long time to be rendered get all the item size, preventing the user to jump to the last item directly for example.

Is there any efficient way to do it? Also, rendering all the rows is so memory consumptive and negates the benefit of using FlatList.

like image 832
user1677104 Avatar asked Aug 13 '19 04:08

user1677104


People also ask

How do I scroll FlatList to a specific index?

If you are using a FlatList in React Native, there's a chance you will want to use the scrollToIndex function to scroll to a certain item's index. Unfortunately, this function is a lot easier to use with fixed item heights where it is easy to implement the required getItemLayout function.

How do you keep the scroll position with FlatList?

In Flatlist set scrollsToTop={false} this will retain position when you navigate back from detail screen.

Is FlatList better than ScrollView?

As opposed to the ScrollView, the FlatList renders only those elements that are currently being displayed on the screen (default: 10 items). Thus, it does not have any impact on the performance of the application. So, it is preferable to use the FlatList Component to display a large list of data.


1 Answers

You can dynamically split your data according to scroll direction. If scroll goes up prepend data to your state and same for opposite direction. Then use onScrollToIndexFailed like this :

<FlatList
  ref={this.flatListRef}
  data={this.state.data}
  renderItem={() => <View> <SomeComponent /> </View>}
  initialNumToRender={this.state.data.length / 5}
  onEndReached={(e) => {
    // Append data
  }}
  onScroll={(e) => {
    if (e.nativeEvent.contentOffset.y == 0) {
      // Prepend data
    }
  }}
  onScrollToIndexFailed={(error) => {
    this.flatListRef.scrollToOffset({ offset: error.averageItemLength * error.index, animated: true });
    setTimeout(() => {
      if (this.state.data.length !== 0 && this.flatListRef !== null) {
        this.flatListRef.scrollToIndex({ index: error.index, animated: true });
      }
    }, 100);
  }}
/>   

You can workaround this issue. This worked for me and took me a lot of time to get that work :))

like image 124
Matin Zadeh Dolatabad Avatar answered Sep 20 '22 22:09

Matin Zadeh Dolatabad