如何检测FlatList滚动是否由手势或scrollToOffset方法触发?



如何判断一个平面列表滚动是由用户手势触发的,还是由scrolltoffset或scrollToIndex方法触发的?

我搜索类似的东西…(不工作)

const onScroll=(event, isGesture)=>{
if(!isGesture)return
}
<FlatList onScroll={onScroll}/>

你可以创建一个ref,在调用scrollToOffsetscrollToIndex之前切换,然后在滚动动画完成后再次切换。

let isGesture = useRef(true).current;

检查这个裁判的价值在你onScroll函数来确定该怎么做。

const onScroll=e=>{
if(!isGesture){
console.log('inorganic scrolling!')
return
}
console.log('Organic scrolling!')
// do your scroll stuff
}

你将遇到的最大问题将是计算出在将ref切换回其默认值之前需要等待多长时间。如果等待的时间太长,那么您可能会错过用户滚动事件,如果等待的时间太短,您将捕获scrollTo动画的结束。遗憾的是,FlatList没有透露任何关于滚动动画持续时间的信息,所以你不得不猜测:

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
}

这里有一个例子

编辑或者,您可以禁用滚动动画并为偏移量提供少量时间:

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

在这里演示

onMomentumScrollEnd只触发用户滚动

const onMomentumScrollEnd=(event)=>{

}
<FlatList onMomentumScrollEnd={onScroll}/>

最新更新