From 5de32c1dee3de9da5ea4c7e169754bf8bf779cca Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 29 Oct 2024 04:49:00 -0700 Subject: [PATCH] Fix RTL ScrollView position when content smaller than container Summary: Noticed in the screenshots of https://github.com/facebook/react-native/pull/47230 that Android's logic of setting scroll content origin to zero, than right aligning scroll offset, won't correctly handle case where content is smaller than scrolling container. We can fix that by only resetting the origin when content overflows container, since we otherwise are not scrollable, and scroll adjustment will not translate. Changelog: [Android][Fixed] - Fix RTL ScrollView position when content smaller than container Differential Revision: D65136654 --- ...dHorizontalScrollContentViewShadowNode.cpp | 7 ++++-- .../examples/ScrollView/ScrollViewExample.js | 23 +++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.cpp index d7975f0ba396..eb7b4ce7e4a5 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/AndroidHorizontalScrollContentViewShadowNode.cpp @@ -17,8 +17,11 @@ void AndroidHorizontalScrollContentViewShadowNode::layout( ConcreteViewShadowNode::layout(layoutContext); // When the layout direction is RTL, we expect Yoga to give us a layout - // that extends off the screen to the left so we re-center it with left=0 - if (layoutMetrics_.layoutDirection == LayoutDirection::RightToLeft) { + // that extends off the screen to the left so we re-center it to be at most + // zero (where the scrolling offset will be adjusted to match if larger than + // parent width on the Android component side). + if (layoutMetrics_.layoutDirection == LayoutDirection::RightToLeft && + layoutMetrics_.frame.origin.x < 0) { layoutMetrics_.frame.origin.x = 0; } } diff --git a/packages/rn-tester/js/examples/ScrollView/ScrollViewExample.js b/packages/rn-tester/js/examples/ScrollView/ScrollViewExample.js index faf56a7bdd14..ae0b34365c56 100644 --- a/packages/rn-tester/js/examples/ScrollView/ScrollViewExample.js +++ b/packages/rn-tester/js/examples/ScrollView/ScrollViewExample.js @@ -287,6 +287,19 @@ const examples: Array = [ ); }, }, + { + name: 'stubbyHorizontalScrollView', + title: ' (horizontal = true) in RTL not filling content\n', + description: + 'A horizontal RTL ScrollView whose content is smaller thatn its containner', + render(): React.Node { + return ( + + + + ); + }, + }, { title: ' enable & disable\n', description: 'ScrollView scrolling behaviour can be disabled and enabled', @@ -541,10 +554,16 @@ const AndroidScrollBarOptions = () => { ); }; -const HorizontalScrollView = (props: {direction: 'ltr' | 'rtl'}) => { +const HorizontalScrollView = (props: { + direction: 'ltr' | 'rtl', + itemCount?: number, +}) => { const {direction} = props; const scrollRef = React.useRef>(); const title = direction === 'ltr' ? 'LTR Layout' : 'RTL Layout'; + const items = + props.itemCount == null ? ITEMS : ITEMS.slice(0, props.itemCount); + return ( {title} @@ -555,7 +574,7 @@ const HorizontalScrollView = (props: {direction: 'ltr' | 'rtl'}) => { horizontal={true} style={[styles.scrollView, styles.horizontalScrollView]} testID={'scroll_horizontal'}> - {ITEMS.map(createItemRow)} + {items.map(createItemRow)}