Make sure that `onSnapToItem` is triggered AFTER scroll animation's completion
bd-arc opened this issue · comments
Currently, React Native doesn't provide a callback for the scrollTo()
method, which is a bummer.
The ScrollView component has a prop onScrollAnimationEnd
, but unfortunately this works on iOS only (even though it is referenced in the Java file). Moreover, a bug currently prevents the callback from being fired with horizontal scrollers.
Another lead would be to link the duration of the scroll animation to a timer before firing the callback. Unfortunately, scrollTo()
doesn't accept a custom duration.
An idea might be to activate momentum events on Android and see if onMomentumScrollEnd
can provide a good enough feedback without impairing performance too much. But this event might not be fired when snapping programatically... Moreover, it is automatically enabled if a momentum callback has been set.
ScrollResponder is another lead worth pursuing...
marginally related to this, inside onSnapToItem
callback the value of this.carousel.currentIndex
is still the previous index not the one we're snapping too.
I noticed this because I'm using
<Carousel
ref={(carousel) => { this.carousel = carousel; }}
onSnapToItem={(index) => {
console.log('snap', index, this.carousel.currentIndex);
this.forceUpdate()
}}
>
{screens}
</Carousel>
<CarouselControls
onPress={(page) => this.carousel.snapToItem(page)}
selected={this.carousel ? this.carousel.currentIndex : 0}
length={screens.length}
/>
CarouselControls
is my custom component that uses this.carousel.currentIndex
so I'm using forceUpdate
instead of duplicating the state in my component, but the currentIndex
is not uptodate
@piuccio Thanks for your feedback! This is pretty strange; I'll take a look at it as soon as possible.
Some answer about this problem ?
Hi @joseygordev, are you referring to @piuccio's issue or to the original one?
Regarding the former, I should be able to take a look at it in the next few days; regarding the latter, we are still awaiting an evolution of React Native's source code. The issue is still pending 6 months later, without any feedback from RN's team...
Hi guys,
I finally had time to dig into this issue. I can confirm that, sadly, it is deeply related to React Native's implementation.
For all the reasons explained in my first post, we can't rely on anything but the onScrollEndDrag
callback when enableMomentum
is disabled. Unfortunately, this means that activeItem
computation will be wrong if you haven't scrolled enough so that the next slide became active. Here is a short screencast of what I mean: http://i.imgur.com/VseNsKh.gif
Since FlatList
doesn't resolve any of the issues, we're kind of stuck right now :-(
I just had an idea worth trying, which is to rely on slide animation's completion and to combine it with a time threshold to "determine" if scroll has ended.
This is clearly far from ideal, but it might still lead to better results than onScrollEndDrag
. I'll keep you posted!
@piuccio @joseygordev Version 2.2.1 should resolve your issue with the faulty index.
I've completely refactored the way callbacks are handled when momentum is disabled. Let's face it: this is hacky since ScrollView
neither provides callbacks to the scrollTo
method nor gives access to a onScrollEnd
event.
Make sure to play with the new props scrollEndDragThrottleValue
and snapCallbackDebounceValue
. Let me know how this works for you.
@joseygordev Note that version 2.3.0 handles no-momentum callbacks way better ;-)