diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 5ec5fb68f05..7a22c36c032 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -48,6 +48,11 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg CGSize _contentSize; NSTimeInterval _lastScrollEventDispatchTime; NSTimeInterval _scrollEventThrottle; + // Flag indicating whether the scrolling that is currently happening + // is triggered by user or not. + // This helps to only update state from `scrollViewDidScroll` in case + // some other part of the system scrolls scroll view. + BOOL _isUserTriggeredScrolling; } + (RCTScrollViewComponentView *_Nullable)findScrollViewComponentViewForView:(UIView *)view @@ -67,6 +72,7 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg _scrollView = [[RCTEnhancedScrollView alloc] initWithFrame:self.bounds]; _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _scrollView.delaysContentTouches = NO; + _isUserTriggeredScrolling = NO; [self addSubview:_scrollView]; _containerView = [[UIView alloc] initWithFrame:CGRectZero]; @@ -204,8 +210,10 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg - (void)_updateStateWithContentOffset { + if (!_state) { + return; + } auto contentOffset = RCTPointFromCGPoint(_scrollView.contentOffset); - _state->updateState([contentOffset](ScrollViewShadowNode::ConcreteState::Data const &data) { auto newData = data; newData.contentOffset = contentOffset; @@ -217,6 +225,7 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg { _scrollView.contentOffset = CGPointZero; _state.reset(); + _isUserTriggeredScrolling = NO; [super prepareForRecycle]; } @@ -224,6 +233,9 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg - (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (!_isUserTriggeredScrolling) { + [self _updateStateWithContentOffset]; + } if (!_eventEmitter) { return; } @@ -243,6 +255,18 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg [self scrollViewDidScroll:scrollView]; } +- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView +{ + _isUserTriggeredScrolling = YES; + return YES; +} + +- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView +{ + _isUserTriggeredScrolling = NO; + [self _updateStateWithContentOffset]; +} + - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self _forceDispatchNextScrollEvent]; @@ -252,6 +276,7 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg } std::static_pointer_cast(_eventEmitter)->onScrollBeginDrag([self _scrollViewMetrics]); + _isUserTriggeredScrolling = YES; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate @@ -288,6 +313,7 @@ static void RCTSendPaperScrollEvent_DEPRECATED(UIScrollView *scrollView, NSInteg std::static_pointer_cast(_eventEmitter)->onMomentumScrollEnd([self _scrollViewMetrics]); [self _updateStateWithContentOffset]; + _isUserTriggeredScrolling = NO; } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView