Skip to content

Commit

Permalink
Fix Issue 10718: Add iOS support for progressViewOffset (facebook#30737)
Browse files Browse the repository at this point in the history
Summary:
Fixes facebook#10718, bringing `progressViewOffset` support to iOS.

Thanks to Taylor123 for the initial PR upon which this fix is based.

## Changelog

[iOS] [Fix] - `progressViewOffset` prop of `RefreshControl` and `VirtualizedList` now works on iOS

Pull Request resolved: facebook#30737

Test Plan:
Tested with quick-and-dirty sample app.

![progressViewOffset-iOS](https://user-images.githubusercontent.com/1563532/104526540-82fe1d80-55b7-11eb-9f99-e025bedf4874.gif)

## Documentation

The corresponding documentation update PR can be found [here](facebook/react-native-website#2441).

Reviewed By: kacieb

Differential Revision: D26813977

Pulled By: sammy-SC

fbshipit-source-id: 45cc5a647d70e44a29c6391b7586cb41ca011bef
  • Loading branch information
davidbiedenbach authored and facebook-github-bot committed Mar 11, 2021
1 parent 896baf7 commit 310a6bc
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -32,6 +36,10 @@ type NativeProps = $ReadOnly<{|
* The title displayed under the refresh indicator.
*/
title?: WithDefault<string, null>,
/**
* Progress view top offset
*/
progressViewOffset?: WithDefault<Float, 0>,

/**
* Called when the view starts refreshing.
Expand Down
10 changes: 5 additions & 5 deletions Libraries/Components/RefreshControl/RefreshControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<{|
Expand All @@ -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,
|}>;

/**
Expand Down Expand Up @@ -162,7 +163,6 @@ class RefreshControl extends React.Component<RefreshControlProps> {
colors,
progressBackgroundColor,
size,
progressViewOffset,
...props
} = this.props;
return (
Expand Down
1 change: 0 additions & 1 deletion Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/**
Expand Down
21 changes: 21 additions & 0 deletions React/Views/RefreshControl/RCTRefreshControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ @implementation RCTRefreshControl {
BOOL _refreshingProgrammatically;
NSString *_title;
UIColor *_titleColor;
CGFloat _progressViewOffset;
}

- (instancetype)init
Expand All @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -172,6 +187,12 @@ - (void)setCurrentRefreshingState:(BOOL)refreshing
_currentRefreshingStateTimestamp = _currentRefreshingStateClock++;
}

- (void)setProgressViewOffset:(CGFloat)offset
{
_progressViewOffset = offset;
[self _applyProgressViewOffset];
}

- (void)refreshControlValueChanged
{
[self setCurrentRefreshingState:super.refreshing];
Expand Down
1 change: 1 addition & 0 deletions React/Views/RefreshControl/RCTRefreshControlManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 310a6bc

Please sign in to comment.