From 3c31e9dd9fbe05da7bb7eaa951ba3d351af6c1d5 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Wed, 29 May 2024 10:01:46 -0700 Subject: [PATCH] clip content offset when scroll view is restored from shadow tree (#44704) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44704 changelog: [internal] Checkout the code comments for explanation. Reviewed By: javache Differential Revision: D57903106 fbshipit-source-id: 202edfa0b93ce222997ed793313cdc3ca32f8818 --- .../ScrollView/RCTScrollViewComponentView.mm | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 5bc1ca6f95c..c1a2eeb1e00 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -319,6 +319,26 @@ static void RCTSendScrollEventForNativeAnimations_DEPRECATED(UIScrollView *scrol auto contentOffset = RCTCGPointFromPoint(data.contentOffset); if (!oldState && !CGPointEqualToPoint(contentOffset, CGPointZero)) { + /* + * When is suspended, it is removed from view hierarchy and its offset is stored in + * state. We want to restore this offset from the state but it must be snapped to be within UIScrollView's + * content to remove any overscroll. + * + * This can happen, for example, with pull to refresh. The UIScrollView will be overscrolled into negative offset. + * If the offset is not adjusted to be within the content area, it leads to a gap and UIScrollView does not adjust + * its offset until user scrolls. + */ + + // Adjusting overscroll on the top. + contentOffset.y = fmax(contentOffset.y, -_scrollView.contentInset.top); + + // Adjusting overscroll on the left. + contentOffset.x = fmax(contentOffset.x, -_scrollView.contentInset.left); + + // TODO: T190695447 - Protect against over scroll on the bottom and right as well. + // This is not easily done because we need to flip the order of method calls for + // ShadowViewMutation::Insert. updateLayout must come before updateState. + _scrollView.contentOffset = contentOffset; }