How can you tell if a flatlist scroll is triggered by a user gesture or by a scrollToOffset or scrollToIndex method?
I search for something like that... (not working)
const onScroll=(event, isGesture)=>{
if(!isGesture)return
}
<FlatList onScroll={onScroll}/>
CodePudding user response:
onMomentumScrollEnd only triggeres on user Scroll
const onMomentumScrollEnd=(event)=>{
}
<FlatList onMomentumScrollEnd={onScroll}/>
CodePudding user response:
You can create a ref that you toggle before you call scrollToOffset
or scrollToIndex
, and then toggle again after the scroll animatino completes.
let isGesture = useRef(true).current;
Check this ref's value in your onScroll
function to determine what to do.
const onScroll=e=>{
if(!isGesture){
console.log('inorganic scrolling!')
return
}
console.log('Organic scrolling!')
// do your scroll stuff
}
The biggest issue you will encounter will be figuring out how long to wait before toggling the ref back to its default value. If you wait too long, then you may miss user scroll events, and if you wait too shortly, you will capture the end of the scrollTo
animation. Sadly, FlatList doesnt reveal anything about its scroll animation duration so you kinda have to guess:
const {width, height} = useWindowDimensions();
let flatListRef = useRef({}).current;
let currentIndex = useRef(0).current;
const listHeight = height;
// simulate inorganic scroll
const randomScroll = ()=>{
// set isGesture to false before doing inorganic scrolling
isGesture = false;
let index = Math.floor(getRandom(0,data.length));
flatListRef?.scrollToIndex({index,viewPosition:0});
// calculate time to wait before setting isGesture back to true
let itemsToPass = Math.abs(currentIndex - index);
let scrollDist = itemsToPass*listHeight;
// i found that scrolling 613 pixels take about 750ms
const baseDist = 613
const baseDuration = 750;
// i doubt this is the formula used to calculate
// flatlist animation duration but it kinda works
const estimatedAnimationDuration = Math.min(
baseDuration**(1 (baseDist/baseDuration))**(itemsToPass/100),
// animation usually doesnt exceeds 1500ms
1500
);
console.log('Passing',itemsToPass,'items will take',estimatedAnimationDuration)
// wait for animation to finish
setTimeout(()=>{
isGesture=true
},estimatedAnimationDuration)
currentIndex = index
}
EDIT
Alternatively, you could disable the scroll animation and provide a small amount of time for the offset:
const randomScroll = () => {
// set isGesture to false before doing inorganic scrolling
isGesture = false;
let index = Math.floor(getRandom(0, data.length));
const scrollConfig = {
index,
viewPosition: 0,
animated:false,
}
flatListRef?.scrollToIndex(scrollConfig);
// calculate time to wait before setting isGesture back to true
let itemsToPass = Math.abs(currentIndex - index);
let scrollDist = itemsToPass * listHeight;
// i found that scrolling 613 pixels take about 750ms
const baseDist = 613;
const baseDuration = 750;
// i doubt this is the formula used to calculate
// flatlist animation duration but it kinda works
const estimatedAnimationDuration = scrollConfig.animated
? Math.min(
baseDuration ** ((1 baseDist / baseDuration) ** (itemsToPass / 100)),
// animation usually doesnt exceeds 1500ms
1500)
: 200
scrollConfig.animated && console.log(
'Passing',
itemsToPass,
'items will take',
estimatedAnimationDuration
);
// wait for animation to finish
setTimeout(() => {
isGesture = true;
}, estimatedAnimationDuration);
currentIndex = index;
};