Reputation: 1095
I got a component that I want to make some sort like filter page at side something looks like this
A
B
C
D
E
F
G
H
.
.
.
once the user scroll until Z, the user can see A back after Z.. it's endless loop using flatList. How do i archieve that ?
Y
Z
A
B
C
D
.
.
.
right now all i test using onEndReached I move back to initial position but it not a good experience. anyone can give a bit tips or guide?
Thanks!
_renderItem = ({item, index}) => (
<Text>{item}</Text>
);
<FlatList
data={['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
showsVerticalScrollIndicator={false}
/>
Upvotes: 3
Views: 8778
Reputation: 3335
you can use the package: react-native-infinite-looping-scroll from https://github.com/prateek3255/react-native-infinite-looping-scroll. here's it's source code.
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import PropTypes from 'prop-types'
export default class InfiniteScroll extends Component {
constructor(props) {
super(props)
this.state = {
data: this.props.data,
end: true,
}
length = this.state.data.length
data = this.state.data.slice()
}
checkScroll({ layoutMeasurement, contentOffset, contentSize }) {
if (this.state.data.length >= length * 3)
this.setState(prevState => ({
data: prevState.data.slice(length * 2)
}))
if (contentOffset.y <= this.props.offset) {
this.setState(prevState => ({
data: [...prevState.data, ...data],
}), () => this.infListRef.scrollToIndex({ index: length, animated: false }))
}
if (layoutMeasurement.height + contentOffset.y >= contentSize.height - this.props.offset && this.state.end) {
this.setState(prevState => ({
data: [...prevState.data, ...data],
end: false
}))
}
else {
this.setState({
end: true
})
}
}
componentDidMount() {
this.setState(prevState => ({
data: [...prevState.data, ...prevState.data]
}))
setTimeout(() => { this.infListRef.scrollToIndex({ animated: false, index: length }) }, 500);
}
render() {
return (
<FlatList
{...this.props}
ref={(ref) => { this.infListRef = ref; }}
data={this.state.data}
renderItem={this.props.renderItem}
onScroll={({ nativeEvent }) => this.checkScroll(nativeEvent)}
showsVerticalScrollIndicator={this.props.showsVerticalScrollIndicator}
/>
);
}
}
InfiniteScroll.propTypes = {
offset: PropTypes.number,
showsVerticalScrollIndicator: PropTypes.bool
}
InfiniteScroll.defaultProps = {
offset: 20,
showsVerticalScrollIndicator: false
};
Upvotes: 2
Reputation: 3717
The best solution without having to scroll to the center I found is using array like object with very big length and use it as data.
const loopedData = {length: 100000} as undefined[]; // created outside component
const initialIndex = originalData
? Math.round(loopedData.length / 2 - originalData.length / 2)
: 0;
<FlatList
...
data={originalData ? loopedData : null}
extraData={originalData}
initialScrollIndex={initialIndex}
getItemLayout={getItemLayout}
...
/>
But in render take data from original array:
const render = (info: ListRenderItemInfo<undefined>) => {
if (!originalData) return null;
const originalItemIndex = getOriginalItemIndex(
info.index,
originalData.length,
initialIndex,
);
return renderItemImpl?.({
index: originalItemIndex,
item: originalData[originalItemIndex],
separators: info.separators,
});
}
Here are some helpers for implementing this approach:
export const getOriginalItemIndex = (
index: number,
originalLength: number,
initialScrollIndex: number,
) => {
return (
(index + originalLength - (initialScrollIndex % originalLength)) %
originalLength
);
};
// used for scrolling to nearest index
export const getNearestToCurrentIndex = (
currentIndex: number,
originalIndex: number,
originalIndexTo: number,
originalLength: number,
) => {
if (originalIndex === originalIndexTo) return currentIndex;
const rightDistance =
originalIndexTo > originalIndex
? originalIndexTo - originalIndex
: originalLength - originalIndex + originalIndexTo;
const leftDistance = originalLength - rightDistance;
const result =
rightDistance <= leftDistance
? currentIndex + rightDistance
: currentIndex - leftDistance;
return result;
};
You can also recenter list when screen disappears but not unmounted, but not necessary.
Upvotes: 0