diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index 46e0ccf36c6e9d..2f0d6c93ed7d93 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -379,4 +379,22 @@ public void setPointerEvents(ReactScrollView view, @Nullable String pointerEvent public void setScrollEventThrottle(ReactScrollView view, int scrollEventThrottle) { view.setScrollEventThrottle(scrollEventThrottle); } + + @ReactProp(name = "internalAndroidApplyInvertedFix") + public void setInternalAndroidApplyInvertedFix(ReactScrollView view, boolean applyFix) { + // Usually when inverting the scroll view we are using scaleY: -1 on the list + // and on the parent container. HOWEVER, starting from android API 33 there is + // a bug that can cause an ANR due to that. Thus we are using different transform + // commands to circumvent the ANR. This however causes the vertical scrollbar to + // be on the wrong side. Thus we are moving it to the other side, when the list + // is inverted. + // See also: + // - https://github.com/facebook/react-native/issues/35350 + // - https://issuetracker.google.com/issues/287304310 + if (applyFix) { + view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT); + } else { + view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_DEFAULT); + } + } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp index fb70d8a6176cab..03463afdfdbe87 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp @@ -319,6 +319,15 @@ ScrollViewProps::ScrollViewProps( rawProps, "scrollToOverflowEnabled", sourceProps.scrollToOverflowEnabled, + {})), + internalAndroidApplyInvertedFix( + CoreFeatures::enablePropIteratorSetter + ? sourceProps.internalAndroidApplyInvertedFix + : convertRawProp( + context, + rawProps, + "internalAndroidApplyInvertedFix", + sourceProps.internalAndroidApplyInvertedFix, {})) {} void ScrollViewProps::setProp( @@ -368,6 +377,7 @@ void ScrollViewProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(snapToEnd); RAW_SET_PROP_SWITCH_CASE_BASIC(contentInsetAdjustmentBehavior); RAW_SET_PROP_SWITCH_CASE_BASIC(scrollToOverflowEnabled); + RAW_SET_PROP_SWITCH_CASE_BASIC(internalAndroidApplyInvertedFix); } } @@ -492,7 +502,11 @@ SharedDebugStringConvertibleList ScrollViewProps::getDebugProps() const { debugStringConvertibleItem( "snapToStart", snapToStart, defaultScrollViewProps.snapToStart), debugStringConvertibleItem( - "snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd)}; + "snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd), + debugStringConvertibleItem( + "internalAndroidApplyInvertedFix", + snapToEnd, + defaultScrollViewProps.internalAndroidApplyInvertedFix)}; } #endif diff --git a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h index dea44da3af5d2b..2c68787a60a184 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h @@ -68,6 +68,7 @@ class ScrollViewProps final : public ViewProps { ContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior{ ContentInsetAdjustmentBehavior::Never}; bool scrollToOverflowEnabled{false}; + bool internalAndroidApplyInvertedFix{false}; #pragma mark - DebugStringConvertible