Scrolling issues with FlatList when rows are variable height

后端 未结 4 2062
时光说笑
时光说笑 2021-02-01 08:11

I\'m using a FlatList where each row can be of different height (and may contain a mix of both text and zero or more images from a remote server).

I cannot

相关标签:
4条回答
  • 2021-02-01 08:33

    So what I think you can do and what you already have the outlets for is to store a collection by the index of the rows layouts onLayout. You'll want to store the attributes that's returned by getItemLayout: {length: number, offset: number, index: number}.

    Then when you implement getItemLayout which passes an index you can return the layout that you've stored. This should resolve the issues with scrollToIndex. Haven't tested this, but this seems like the right approach.

    0 讨论(0)
  • 2021-02-01 08:34

    Use scrollToOffset() instead:

        export default class List extends React.PureComponent {
    
            // Gets the total height of the elements that come before
            // element with passed index
            getOffsetByIndex(index) {
                let offset = 0;
                for (let i = 0; i < index; i += 1) {
                    const elementLayout = this._layouts[i];
                    if (elementLayout && elementLayout.height) {
                        offset += this._layouts[i].height;
                    }
                }
                return offset;
            }
    
            // Gets the comment object and if it is a comment
            // is in the list, then scrolls to it
            scrollToComment(comment) {
                const { list } = this.props;
                const commentIndex = list.findIndex(({ id }) => id === comment.id);
                if (commentIndex !== -1) {
                    const offset = this.getOffsetByIndex(commentIndex);
                    this._flatList.current.scrollToOffset({ offset, animated: true });
                }
            }
    
            // Fill the list of objects with element sizes
            addToLayoutsMap(layout, index) {
                this._layouts[index] = layout;
            }
    
            render() {
                const { list } = this.props;
    
                return (
                    <FlatList
                        data={list}
                        keyExtractor={item => item.id}
                        renderItem={({ item, index }) => {
                            return (
                                <View
                                    onLayout={({ nativeEvent: { layout } }) => {
                                        this.addToLayoutsMap(layout, index);
                                    }}
                                >
                                    <Comment id={item.id} />
                                </View>
                            );
                        }}
                        ref={this._flatList}
                    />
                );
            }
        }
    
    1. When rendering, I get the size of each element of the list and write it into an array:

    onLayout={({ nativeEvent: { layout } }) => this._layouts[index] = layout}

    1. When it is necessary to scroll the screen to the element, I summarize the heights of all the elements in front of it and get the amount to which to scroll the screen (getOffsetByIndex method).

    2. I use the scrollToOffset method:

    this._flatList.current.scrollToOffset({ offset, animated: true });

    (this._flatList is ref of FlatList)

    0 讨论(0)
  • 2021-02-01 08:49

    Have you tried scrollToEnd?

    http://facebook.github.io/react-native/docs/flatlist.html#scrolltoend

    As the documentation states, it may be janky without getItemLayout but for me it does work without it

    0 讨论(0)
  • 2021-02-01 08:49

    I did not find any way to use getItemLayout when the rows have variable heights , So you can not use initialScrollIndex .

    But I have a solution that may be a bit slow: You can use scrollToIndex , but when your item is rendered . So you need initialNumToRender . You have to wait for the item to be rendered and after use scrollToIndex so you can not use scrollToIndex in componentDidMount .

    The only solution that comes to my mind is using scrollToIndex in onViewableItemsChanged . Take note of the example below : In this example, we want to go to item this.props.index as soon as this component is run

    constructor(props){
    
            this.goToIndex = true;
    
        }
    
    render() {
            return (
    
                    <FlatList
                        ref={component => {this.myFlatList = component;}}
                        data={data}
                        renderItem={({item})=>this._renderItem(item)}
                        keyExtractor={(item,index)=>index.toString()}
                        initialNumToRender={this.props.index+1}
                        onViewableItemsChanged={({ viewableItems }) => {
                            if (this.goToIndex){
                                this.goToIndex = false;
                                setTimeout(() => { this.myFlatList.scrollToIndex({index:this.props.index}); }, 10);
                            }
                        }}
                    />
    
            );
        }
    
    0 讨论(0)
提交回复
热议问题