diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js index 4947b1e31df3b3..fa4791f2ab620c 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js @@ -8,7 +8,11 @@ * @flow strict-local */ -import type {DirectEventHandler, WithDefault} from '../../Types/CodegenTypes'; +import type { + DirectEventHandler, + Float, + WithDefault, +} from '../../Types/CodegenTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheet'; import type {ViewProps} from '../View/ViewPropTypes'; import * as React from 'react'; @@ -32,6 +36,10 @@ type NativeProps = $ReadOnly<{| * The title displayed under the refresh indicator. */ title?: WithDefault, + /** + * Progress view top offset + */ + progressViewOffset?: WithDefault, /** * Called when the view starts refreshing. diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js index 48bafb5ca62c83..0f0a16dbbccfc5 100644 --- a/Libraries/Components/RefreshControl/RefreshControl.js +++ b/Libraries/Components/RefreshControl/RefreshControl.js @@ -52,10 +52,6 @@ type AndroidProps = $ReadOnly<{| * Size of the refresh indicator. */ size?: ?('default' | 'large'), - /** - * Progress view top offset - */ - progressViewOffset?: ?number, |}>; export type RefreshControlProps = $ReadOnly<{| @@ -72,6 +68,11 @@ export type RefreshControlProps = $ReadOnly<{| * Whether the view should be indicating an active refresh. */ refreshing: boolean, + + /** + * Progress view top offset + */ + progressViewOffset?: ?number, |}>; /** @@ -162,7 +163,6 @@ class RefreshControl extends React.Component { colors, progressBackgroundColor, size, - progressViewOffset, ...props } = this.props; return ( diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 7daac9f077f20e..dcf4dd50b99f53 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -246,7 +246,6 @@ type OptionalProps = {| persistentScrollbar?: ?boolean, /** * Set this when offset is needed for the loading indicator to show correctly. - * @platform android */ progressViewOffset?: number, /** diff --git a/React/Views/RefreshControl/RCTRefreshControl.m b/React/Views/RefreshControl/RCTRefreshControl.m index 6985c38bce40b2..91b0e42e3d773e 100644 --- a/React/Views/RefreshControl/RCTRefreshControl.m +++ b/React/Views/RefreshControl/RCTRefreshControl.m @@ -21,6 +21,7 @@ @implementation RCTRefreshControl { BOOL _refreshingProgrammatically; NSString *_title; UIColor *_titleColor; + CGFloat _progressViewOffset; } - (instancetype)init @@ -40,6 +41,7 @@ - (instancetype)init - (void)layoutSubviews { [super layoutSubviews]; + [self _applyProgressViewOffset]; // If the control is refreshing when mounted we need to call // beginRefreshing in layoutSubview or it doesn't work. @@ -120,6 +122,19 @@ - (void)endRefreshingProgrammatically } } +- (void)_applyProgressViewOffset +{ + // 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 + // multiple times. + UIView *scrollView = self.superview; + UIView *target = scrollView.superview; + CGPoint rawOffset = CGPointMake(0, _progressViewOffset); + CGPoint converted = [self convertPoint:rawOffset fromView:target]; + self.frame = CGRectOffset(self.frame, 0, converted.y); +} + - (NSString *)title { return _title; @@ -172,6 +187,12 @@ - (void)setCurrentRefreshingState:(BOOL)refreshing _currentRefreshingStateTimestamp = _currentRefreshingStateClock++; } +- (void)setProgressViewOffset:(CGFloat)offset +{ + _progressViewOffset = offset; + [self _applyProgressViewOffset]; +} + - (void)refreshControlValueChanged { [self setCurrentRefreshingState:super.refreshing]; diff --git a/React/Views/RefreshControl/RCTRefreshControlManager.m b/React/Views/RefreshControl/RCTRefreshControlManager.m index 3152b1c8069020..87c997a8edda4f 100644 --- a/React/Views/RefreshControl/RCTRefreshControlManager.m +++ b/React/Views/RefreshControl/RCTRefreshControlManager.m @@ -25,6 +25,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(title, NSString) RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat) RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing) {