ScrollView: momentum scroll events
necolas opened this issue · 9 comments
Look into supporting momentum scroll events.
I guess that to add support for the scroll momentum callbacks there needs to be a way to detect if the scroll is done with momentum.
You could always check for the scroll speed, but that is not really the same thing as you call do a scroll movement fast without it having momentum.
Is anyone aware of any existing Javascript implementations where such gesture would be detected?
My initial thought is that if a scroll is initiated by a touch, and scroll events are still firing while there is no active touch, we're in a "momentum" phase of the scroll. I don't think momentum events can exist for mouse/wheel-triggered scrolls. And the drag start event would fire when touch-scrolling starts, and drag end would fire when touch-scrolling ends. But would have to check when the events fire for native to confirm.
I don't think momentum events can exist for mouse/wheel-triggered scrolls
At least on macos with a trackpad you can experience them in all browsers.
Might this help to finish touchable support as some issues with those might be related to some missing events (eg: for scroll responder?)
me too
For anyone needing a temp workaround I made a hook...
// hooks.js
export const useWebOnScroll = ({ onScroll, onScrollEnd }) => {
const lastScrollEvent = useRef(null);
const scrollEndTimeout = useRef(null);
const handleWebScroll = event => {
onScroll(event);
const timestamp = Date.now();
if (scrollEndTimeout.current) {
clearTimeout(scrollEndTimeout.current);
}
if (lastScrollEvent.current) {
// Scroll ended
scrollEndTimeout.current = setTimeout(() => {
if (lastScrollEvent.current === timestamp) {
lastScrollEvent.current = null;
onScrollEnd && onScrollEnd(event);
}
}, 500);
}
lastScrollEvent.current = timestamp;
};
useEffect(() => {
return () => {
scrollEndTimeout.current && clearTimeout(scrollEndTimeout.current);
};
}, []);
return handleWebScroll;
};
// Component.js
const Component = ({onScroll, onScrollEnd}) => {
const handleWebScroll = useWebOnScroll({ onScroll, onScrollEnd })
<ScrollView onScroll={Platform.select({ web: handleWebScroll, default: onScroll })} />
}
Anyone know if this has been fixed or if there's another way of achieving this effect on RN web?
Here's my solution: #2249 (comment)
For anyone needing a temp workaround I made a hook...
// hooks.js export const useWebOnScroll = ({ onScroll, onScrollEnd }) => { const lastScrollEvent = useRef(null); const scrollEndTimeout = useRef(null); const handleWebScroll = event => { onScroll(event); const timestamp = Date.now(); if (scrollEndTimeout.current) { clearTimeout(scrollEndTimeout.current); } if (lastScrollEvent.current) { // Scroll ended scrollEndTimeout.current = setTimeout(() => { if (lastScrollEvent.current === timestamp) { lastScrollEvent.current = null; onScrollEnd && onScrollEnd(event); } }, 500); } lastScrollEvent.current = timestamp; }; useEffect(() => { return () => { scrollEndTimeout.current && clearTimeout(scrollEndTimeout.current); }; }, []); return handleWebScroll; }; // Component.js const Component = ({onScroll, onScrollEnd}) => { const handleWebScroll = useWebOnScroll({ onScroll, onScrollEnd }) <ScrollView onScroll={Platform.select({ web: handleWebScroll, default: onScroll })} /> }
There is a problem with this solution. When the finger drags the scroll wheel to roll a certain distance without releasing the finger for about 1 second, releasing the finger will not trigger onScrollEnd