使用可变项目大小滚动到 FlatList 中某个索引的有效方法 [英] Efficient way to scroll to certain index in FlatList with variable item size

查看:28
本文介绍了使用可变项目大小滚动到 FlatList 中某个索引的有效方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 react-native 中向 FlatList 上的某些索引功能添加滚动/跳转时遇到问题.我的 FlatList 项目的大小(高度)各不相同,这使我无法实现 getItemLayout,因为这需要我事先了解 FlatList 项目的大小,因此我不能使用 scrollToIndex(这需要实现 getItemLayout).

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).

我的解决方案是在使用 onLayout 呈现时获取每个项目的大小,并将它们与它们的索引进行映射.然后我可以使用每个项目的大小来获取它们的偏移量并使用 scrollToOffset 跳转到给定的项目(通过在下面的代码中使用 scrollToItem 函数).这里的问题是,在渲染该项目之前,我无法跳转到该项目.我的临时解决方案是将 initialNumberToRender 调整为接近数据数量并将 windowSize 道具设置得尽可能高,以便渲染所有项目(即使用户不会向下滚动).

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}
    />
  );
}

这个方案适用于少量数据,但是当数据很大(包含~300行)时,需要很长时间才能渲染获取所有项目大小,防止用户直接跳转到最后一个项目例如.

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.

有什么有效的方法吗?此外,渲染所有行会消耗大量内存,并且会抵消使用 FlatList 的好处.

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

推荐答案

您可以根据滚动方向动态拆分数据.如果滚动上升,则将数据添加到您的状态,相反方向则相同.然后像这样使用 onScrollToIndexFailed :

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 :))

这篇关于使用可变项目大小滚动到 FlatList 中某个索引的有效方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆