react-native-windows icon indicating copy to clipboard operation
react-native-windows copied to clipboard

Implement native inverted behaviors for ScrollView

Open rozele opened this issue 4 years ago • 5 comments

This PR modifies ScrollViewManager and VirtualizedList to work around the limitations of the RN core approach to list inversion. Specifically, the RN core approach to list inversion uses scroll axis transforms to flip the list content. While this creates the visual appearance of an inverted list, scrolling the list via keyboard or mouse wheel results in inverted scroll direction.

To accomplish native inverted scroll behaviors, we focused on four expected behaviors of inverted lists:

  1. When content loads "above" the view port in an inverted list, the visual content must remain anchored (as if the content renders below it in a non-inverted list).
  2. When scrolled to the "start" of an inverted list (in absolute terms, the bottom of the scroll view), content appended to the start of the list must scroll into view synchronously (i.e., no delay between content rendering and view port changing).
  3. When content renders on screen, it must render from bottom to top, so render passes that take multiple frames do not appear to scroll to the start of the list.
  4. When imperatively scrolling to the "start" of the content, we must always scroll to the latest content, even if the content rendered after the scroll-to-start animation already began.

For 1., we leverage the XAML CanBeScrollAnchor property on each top-level item in the list view. While this is an imperfect solution (re-rendering of this content while in the view port can result in view port shifts as new content renders above), it is a good trade-off of performance and functionality.

For 2., we leverage the XAML HorizontalAnchorRatio and VerticalAnchorRatio properties. XAML has a special case for inverted lists when setting these property values to 1.0. It instructs XAML to synchronously scroll to and render new content when scrolled to the bottom edge of the ScrollViewer.

For 3., we leverage Yoga's implementation of flexDirection: column-reverse and flexDirection: row-reverse to ensure content is rendered from bottom to top.

For 4., we implemented ScrollViewViewChanger to continuously check if the target scroll offset has changed since starting an animated scroll-to-end operation. If the target scroll offset no longer matches the scrollable extent of the ScrollViewer, we update the target offset by calling ChangeView again.

There are two known limitations to this change:

  1. This implementation does not yet support list virtualization, so you must set disableVirtualization={true} when you set inverted={true}
  2. This implementation does not yet support the visual overlay for debug={true}, which is really only useful when virtualization is enabled.

Fixes #4098

Testing

Note: in the video, I'm using the scroll wheel and the ScrollView is scrolling in the correct direction:

https://user-images.githubusercontent.com/1106239/182451523-f0ed3002-2dc8-4aaa-939f-afb0dbea176e.mp4

Microsoft Reviewers: Open in CodeFlow

rozele avatar Aug 18 '21 15:08 rozele

Also pushed some of the platform agnostic changes to VirtualizedList in RN Core: https://github.com/facebook/react-native/pull/32038

rozele avatar Aug 18 '21 16:08 rozele

This is not super immediately clear, but @react-native-windows/virtualized-list is used for more than just XAML. It is also used for the Office internal NetUI platform.

What it basically means is that we can't assume its behavior only affects XAML. It is more of a staging package for upstream. We can do special behavior using Platform.OS checks though, or through other Platform APIs.

NickGerleman avatar Aug 19 '21 12:08 NickGerleman

Bulk marking PRs without activity in the last 14 days as needing author feedback. This helps keep all active PRs visible on the first page of PRs. msftbot will close this PR in two weeks if the label is not removed. Please feel free to remove the label if you are still actively working on this.

NickGerleman avatar Nov 14 '21 21:11 NickGerleman

This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 7 days. It will be closed if no further activity occurs within 7 days of this comment.

ghost avatar Nov 22 '21 00:11 ghost

Note, switching from inverted=false to inverted=true is not really a supported scenario, so in order to test, you'll have to modify the FlatList-basic.js example from RNTester to default to inverted on first render.

rozele avatar Aug 02 '22 18:08 rozele

I believe decision was that this PR will not be taken into RNW on Paper. Tagging with Needs Attention to confirm decision in triage and close.

chiaramooney avatar Mar 29 '23 22:03 chiaramooney

Discussed in PR triage. Decision to not take change for Paper architecture still stands.

chiaramooney avatar Apr 12 '23 23:04 chiaramooney