From a8be335a37eb792a7c6ccb7f577459020a2fc43c Mon Sep 17 00:00:00 2001 From: "Deepanshu.shukla" Date: Fri, 23 Aug 2024 04:50:46 -0700 Subject: [PATCH] fix (iOS): refresh control not behaving correctly if it is offscreen (#45996) Summary: FIXES https://github.com/facebook/react-native/issues/45858 When working with UIRefreshControl in a custom React Native component, we encountered a problem where the refresh control did not behave correctly if it was offscreen. Specifically, attempts to programmatically begin or end refreshing were ignored if the control was not visible. This typically manifested as the refresh control not updating its state properly when it was re-rendered or moved in the view hierarchy. Happening only on old-arch. **Problem Details** **Offscreen Refresh Control Ignored:** The UIRefreshControl would ignore calls to beginRefreshing and endRefreshing if it was not currently visible on the screen. **Inconsistent State:** The internal state _currentRefreshingState might not match the actual state of the UIRefreshControl, leading to unexpected behavior. **Steps to Fix** **Track Visibility with didMoveToWindow:** Implement the didMoveToWindow method to track when the refresh control is added to or removed from the window. Use a flag _hasMovedToWindow to keep track of this state. And check this flag should be true whenever we start or end refreshing ## Changelog: [IOS] [FIXED] - Fixed an issue where the refresh control would not behave correctly if it was offscreen. Pull Request resolved: https://github.com/facebook/react-native/pull/45996 Test Plan: Issue Screen recording https://github.com/user-attachments/assets/73b45c27-19c2-4eeb-991e-33b45f0a6d97 Fix Screen Recording : https://github.com/user-attachments/assets/ffc6b6e6-fc68-498c-abdf-3144c31caa86 Reviewed By: realsoelynn Differential Revision: D61657472 Pulled By: cipolleschi fbshipit-source-id: 7a369f8e3ca902536a7608fbe1b89cec7734c418 --- .../Views/RefreshControl/RCTRefreshControl.m | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/packages/react-native/React/Views/RefreshControl/RCTRefreshControl.m index b09e6530c24..53bfd047035 100644 --- a/packages/react-native/React/Views/RefreshControl/RCTRefreshControl.m +++ b/packages/react-native/React/Views/RefreshControl/RCTRefreshControl.m @@ -22,6 +22,7 @@ NSString *_title; UIColor *_titleColor; CGFloat _progressViewOffset; + BOOL _hasMovedToWindow; } - (instancetype)init @@ -32,6 +33,7 @@ _currentRefreshingStateTimestamp = 0; _isInitialRender = true; _currentRefreshingState = false; + _hasMovedToWindow = NO; } return self; } @@ -56,8 +58,22 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) _isInitialRender = false; } +- (void)didMoveToWindow +{ + [super didMoveToWindow]; + + if (self.window) { + _hasMovedToWindow = YES; + } else { + _hasMovedToWindow = NO; + } +} + - (void)beginRefreshingProgrammatically { + if (!_hasMovedToWindow) + return; + UInt64 beginRefreshingTimestamp = _currentRefreshingStateTimestamp; _refreshingProgrammatically = YES; @@ -92,6 +108,8 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) - (void)endRefreshingProgrammatically { + if (!_hasMovedToWindow) + return; // The contentOffset of the scrollview MUST be greater than the contentInset before calling // endRefreshing otherwise the next pull to refresh will not work properly. UIScrollView *scrollView = self.scrollView;