Skip to content

Commit

Permalink
Fix onMomentumScrollEnd dispatching on dismount
Browse files Browse the repository at this point in the history
Summary:
This change is a follow-up to facebook#46277. 

This fixes two small issues:
1. `onMomentumScrollEnd` would dispatch when a scroll view is unmounted, regardless if the view was in motion or not
1. `scrollToOffset` would fire `onMomentumScrollEnd` regardless if animations were turned on or off

Changelog:
[iOS][Fixed] - Fixed `onMomentumScrollEnd` event not firing on unmount when the scroll view is not in motion

Differential Revision: D65559586
  • Loading branch information
Abbondanzo authored and facebook-github-bot committed Nov 6, 2024
1 parent 125e541 commit 49ae6d1
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -731,25 +731,29 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[self _handleFinishedScrolling:scrollView];

if (!_eventEmitter) {
return;
}

static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onMomentumScrollEnd([self _scrollViewMetrics]);
}

- (void)didMoveToWindow
- (void)willMoveToWindow:(UIWindow *)newWindow
{
[super didMoveToWindow];

if (!self.window) {
[super willMoveToWindow:newWindow];
if (!newWindow) {
// The view is being removed, ensure that the scroll end event is dispatched
[self _handleScrollEndIfNeeded];
}
}

- (void)_handleScrollEndIfNeeded
{
if (_scrollView.isDecelerating || !_scrollView.isTracking) {
if (!_eventEmitter) {
return;
if (_scrollView.isDecelerating) {
if (_eventEmitter) {
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onMomentumScrollEnd([self _scrollViewMetrics]);
}
static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onMomentumScrollEnd([self _scrollViewMetrics]);

[self _updateStateWithContentOffset];
_isUserTriggeredScrolling = NO;
Expand All @@ -760,12 +764,6 @@ - (void)_handleFinishedScrolling:(UIScrollView *)scrollView
{
[self _forceDispatchNextScrollEvent];
[self scrollViewDidScroll:scrollView];

if (!_eventEmitter) {
return;
}

static_cast<const ScrollViewEventEmitter &>(*_eventEmitter).onMomentumScrollEnd([self _scrollViewMetrics]);
[self _updateStateWithContentOffset];
}

Expand Down
12 changes: 6 additions & 6 deletions packages/react-native/React/Views/ScrollView/RCTScrollView.m
Original file line number Diff line number Diff line change
Expand Up @@ -860,16 +860,16 @@ - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)vi
RCT_FORWARD_SCROLL_EVENT(scrollViewDidEndZooming : scrollView withView : view atScale : scale);
}

- (void)didMoveToWindow
- (void)willMoveToWindow:(UIWindow *)newWindow
{
[super didMoveToWindow];
if (self.window == nil) {
[super willMoveToWindow:newWindow];
if (!newWindow) {
// Check if the ScrollView was in motion
if (_scrollView.isDecelerating || !_scrollView.isTracking) {
if (_scrollView.isDecelerating) {
// Trigger the onMomentumScrollEnd event manually
RCT_SEND_SCROLL_EVENT(onMomentumScrollEnd, nil);
// We can't use the RCT_FORWARD_SCROLL_EVENT here beacuse the `_cmd` parameter passed
// to `respondsToSelector` is the current method - so it will be `didMoveToWindow` - and not
// We can't use the RCT_FORWARD_SCROLL_EVENT here because the `_cmd` parameter passed
// to `respondsToSelector` is the current method - so it will be `willMoveToWindow` - and not
// `scrollViewDidEndDecelerating` that is passed.
for (NSObject<UIScrollViewDelegate> *scrollViewListener in _scrollListeners) {
if ([scrollViewListener respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) {
Expand Down

0 comments on commit 49ae6d1

Please sign in to comment.