necolas / react-native-web

Cross-platform React UI packages
https://necolas.github.io/react-native-web
MIT License
21.55k stars 1.78k forks source link

ScrollView: momentum scroll events #1021

Open necolas opened 6 years ago

necolas commented 6 years ago

Look into supporting momentum scroll events.

kristerkari commented 5 years ago

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?

necolas commented 5 years ago

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.

MoOx commented 5 years ago

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?)

RichardLindhout commented 5 years ago

https://css-tricks.com/snippets/css/momentum-scrolling-on-ios-overflow-elements/

zxymgl commented 3 years ago

me too

MorganTrudeau commented 2 years ago

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 })} />
}
Ryanjso commented 2 years ago

Anyone know if this has been fixed or if there's another way of achieving this effect on RN web?

nandorojo commented 11 months ago

Here's my solution: https://github.com/necolas/react-native-web/issues/2249#issuecomment-1736457705