From 0df59d4f03f79c0fcb9ede2d21bf4d49c97c21ef Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Tue, 29 Oct 2024 16:29:36 -0700 Subject: [PATCH] Fix RTL ScrollView position when content smaller than container (#47280) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/47280 Noticed in the screenshots of https://github.com/facebook/react-native/pull/47230 that Android's logic of setting scroll content origin to zero, then 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 Reviewed By: rshest Differential Revision: D65136654 fbshipit-source-id: 2818ff6360cbfac64d7e57bdcbbe8c0a9b4bbb97 --- ...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 d7975f0ba39..eb7b4ce7e4a 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 faf56a7bdd1..ae0b34365c5 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)}