Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScrollView: scrolling direction when using inverted prop #995

Closed
tafelito opened this issue Jun 13, 2018 · 20 comments
Closed

ScrollView: scrolling direction when using inverted prop #995

tafelito opened this issue Jun 13, 2018 · 20 comments

Comments

@tafelito
Copy link

tafelito commented Jun 13, 2018

The problem
When using FlatList with inverted prop, the mouse scrolling direction is also inverted. I'm not sure if this is an issue per se, but I think only the content of the list should be inverted and not the direction of the scroll. I worked on an implementation for the same feature for the RLV and I tried to handle this on the onWheel event reversing the scroll direction of the container. This only happens on desktops, mobiles scroll is different so it works fine there.

How to reproduce
Just using the FlatList with inverted={true}
https://codesandbox.io/s/y21534vlyx

Expected behavior
Invert list content but keep mouse scrolling direction unchanged

Environment (include versions). Did this work in previous versions?

  • OS:
  • Device:
  • Browser: Chrome, Safari
  • React Native for Web (version):^0.8.3
  • React (version): 16.4

Is this something that could be done here as well?

Thanks!

@necolas
Copy link
Owner

necolas commented Jun 14, 2018

Is this something that could be done here as well?

Sounds like a good idea

@tafelito
Copy link
Author

Sounds like a good idea meaning, I'll implement this at some point, or sounds like a good idea for a PR? 😄

Pretty much what I did is, in case inverted is true, I listen to the onWheel event and then reverse the scroll by scrolling to Y minus the delta Y (or X in case of horizontal scrolling). Not sure where this should be implemented here, ScrollResponder maybe?

@necolas
Copy link
Owner

necolas commented Jun 14, 2018

I'm open to a PR if you feel like it. No worries if not. Off the top of my head, I'm not sure where the best place for this to go is but can help figure that out if you're going to try

@tafelito
Copy link
Author

tafelito commented Jun 15, 2018 via email

@necolas
Copy link
Owner

necolas commented Jun 16, 2018

Cool. This setup guide will get you started https://github.com/necolas/react-native-web/blob/master/.github/CONTRIBUTING.md

@tafelito
Copy link
Author

tafelito commented Jun 19, 2018

So I saw that I can add the onWheel prop to the scrollProps in the VirtualizedList and I could set the this._scrollRef.getScrollableNode().scrollTop but I'm not sure that's the best way of doing it, eve if I can calculate the correct delta for the position.
I also tried a different approach but didn't work either. Instead of scaling the elements with -1, I used flexDirection to reverse the scrollview entirely but even though the items are reversed, they are still mounted in the same order, so you'll see how the items are pushed down while loading. So it's not a solution.

@necolas necolas changed the title scrolling direction when using inverted prop ScrollView: scrolling direction when using inverted prop Jul 7, 2018
@mglagola
Copy link

@tafelito did you ever find a solution?

@tafelito
Copy link
Author

tafelito commented Jul 11, 2018 via email

@tafelito
Copy link
Author

tafelito commented Aug 7, 2018

@necolas are you using FlatList at Twitter Lite? Because I saw that the messages window uses an inverted scroll and the direction works fine there.

Also I noticed that the home page uses some sort of window scroller but on the chat screen you can only scroll on the list and not outside

@necolas
Copy link
Owner

necolas commented Aug 7, 2018

No. Twitter PWA uses a custom scroller that isn't integrated with React Native at all, i.e., no support for the responder system etc

@danalloway
Copy link
Contributor

did some work on this over in #1241

@necolas necolas added this to the Flare milestone Mar 4, 2019
@unadlib
Copy link

unadlib commented May 3, 2019

I've had the same issue, and I'm not sure it doesn't seem to have a fix plan?

@raphaelrk
Copy link

raphaelrk commented Jul 14, 2019

Here's a version of that same codesandbox example with some scrolljacking (this._scrollNode.scrollTop -= e.deltaY;) to invert the scroll direction and a trick (transform: translate3d(0,0,0) scaleY(-1)) to force hardware acceleration for better scroll performance: https://codesandbox.io/s/react-native-h32if

Tested on macOS Mojave FF/Safari/Chrome July 14 2019


Update Dec 14 2020: Hooks version. Still working for me on a new project, not perfect but it's good enough

  // invert scrolling
  const flatlistRef = useRef();
  useEffect(() => {
    let scrollNode = flatlistRef.current && flatlistRef.current.getScrollableNode();
    if (!scrollNode) return;
    const listener = scrollNode.addEventListener("wheel", e => {
      scrollNode.scrollTop -= e.deltaY;
      e.preventDefault();
    });
    flatlistRef.current.setNativeProps({ style: { transform: "translate3d(0,0,0) scaleY(-1)" } });
    return () => scrollNode.removeEventListener("wheel", listener);
  }); // needs to run any time flatlist mounts

@shaylew
Copy link

shaylew commented Aug 16, 2019

There's also arrow keys, page up/page down, home/end, and mousewheel drag to consider. I think I've come up with a proof of concept for simpler way to do this that doesn't require reimplementing each type of scrolling: https://jsfiddle.net/4t2uyfpz/1/

The idea is to keep two scrollable elements: a wrapper with a visible scrollbar for the user, and an inverted inner element with position: sticky that gets scrolled by the script. Scroll events -- mousewheel or keyboard -- move the wrapper's scrollbar and we scroll the inner content accordingly. If items get added or removed inside the inverted list we scroll and resize the wrapper to keep it in sync.

(Right now there's some weird behavior where if you scroll to the top and then remove N elements, Chrome -- and only Chrome -- keeps you stuck to the top until you either scroll manually or add N+1 elements back. I'm not sure exactly what's up with that but there's hopefully a workaround.)

@davidfant

This comment has been minimized.

@vmaark
Copy link

vmaark commented May 18, 2020

One thing to note is that on Firefox the scroll direction works correctly.

For the workaround codesandbox, here is the function component version:
https://codesandbox.io/s/react-native-dsyse

@divonelnc

This comment has been minimized.

@necolas necolas removed this from the Flare milestone Dec 8, 2020
@smithydll
Copy link

@raphaelrk I had to add flatlistRef.current to the useEffect dependency otherwise the content in the flatlist would fire the effect several times

useEffect(() => {

[snip]

}, [flatlistRef.current]); // needs to run any time flatlist mounts

@roryabraham
Copy link
Contributor

roryabraham commented Apr 27, 2022

Heads up @staltz and @necolas – we've been using a workaround for the inverted wheel event thing for a while now. I saw this commit is in the pipeline to fix this issue, and it's more or less the same as the workaround we've been using.

However, we did have someone report an edge case with this solution though – if the list is in focus then pressing ArrowDown scrolls you up and ArrowUp scrolls you down. Maybe worth fixing for accessibility reasons?

@staltz
Copy link
Contributor

staltz commented Apr 27, 2022

@roryabraham We solved the keyboard problem like this: https://github.com/staltz/manyverse/blob/master/patches/react-native-web%2B0.17.6.patch (I think it's too ugly to make an upstream PR)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests