From 0062b10b56985c4556011fbbb8d43f0a038d359e Mon Sep 17 00:00:00 2001 From: Rafael Date: Thu, 17 Nov 2022 08:06:41 -0800 Subject: [PATCH] RCTRefreshControl: Updates progressOffset behaviour to prevent it from being applied by default (#35281) Summary: UIRefreshControl has a tight integration with iOS in terms of UINavigationBar/UIScrollView. In this regard, whenever there's a UIScrollView with a UINavigationBar on top, the OS automatically adjusts the contentInset of the UIScrollView to reflect that (something that is exposed to React Native). In a similar manner, UIScrollView passes this along to the attached UIRefreshControl. By setting the frame manually, the RCTRefreshControl component was preventing this behavior. Although having the option is desired, it should not be done by default. In the past it was possible to adjust for this by manually setting the correct value, calculating the statusBar's height/safeAreaInsets.top and appending 44pt (the UINavigationBar height). However, due to changes related to the Dynamic Island (see [here](https://useyourloaf.com/blog/iphone-14-screen-sizes)), the safe area and the status bar size no longer align, making this calculation more tricky. In summary: this changes allows `progressViewOffset` to exist (in order to maintain feature parity with Android) but provides the opportunity for the OSs default behavior to kick in when applicable. | Applying by default | Not applying by default (this change) | :-------------------------:|:-------------------------: ![](https://user-images.githubusercontent.com/753361/200828632-0c9aa605-770c-47be-a825-1e061478c2b4.gif) | ![](https://user-images.githubusercontent.com/753361/200828664-dded9a47-bdbc-4b88-8ab7-92a76cea47e8.gif) ## Changelog [iOS] [Fixed] - Fix application of _progressViewOffset in RCTRefreshControl to not occur by default (when value is unset) Pull Request resolved: https://github.com/facebook/react-native/pull/35281 Test Plan: The GIFs attached display the behavior as expected/unexpected. I'm unaware of any tests written for RCTRefreshControl that could be improved to cover this change. Notes appreciated. Reviewed By: sammy-SC Differential Revision: D41302080 Pulled By: cipolleschi fbshipit-source-id: a2a8e6ef1dcc2e73220c2a182b4516f3bbd94f60 --- React/Views/RefreshControl/RCTRefreshControl.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/React/Views/RefreshControl/RCTRefreshControl.m b/React/Views/RefreshControl/RCTRefreshControl.m index d6c6e487ab0658..b09e6530c24841 100644 --- a/React/Views/RefreshControl/RCTRefreshControl.m +++ b/React/Views/RefreshControl/RCTRefreshControl.m @@ -117,6 +117,13 @@ - (void)endRefreshingProgrammatically - (void)_applyProgressViewOffset { + // Setting the UIRefreshControl's frame breaks integration with ContentInset from the superview + // if it is a UIScrollView. This integration happens when setting the UIScrollView's .refreshControl + // property. For this reason, setting the frame manually should be avoided, if not needed. + if (_progressViewOffset == 0.f) { + return; + } + // progressViewOffset must be converted from the ScrollView parent's coordinate space to // the coordinate space of the RefreshControl. This ensures that the control respects any // offset in the view hierarchy, and that progressViewOffset is not inadvertently applied