Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIRefreshControl added to scroll view #4205

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
var Platform = require('Platform');
var PointPropType = require('PointPropType');
var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
var React = require('React');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var RCTUIManager = require('NativeModules').UIManager;
Expand Down Expand Up @@ -279,6 +280,21 @@ var ScrollView = React.createClass({
* @platform ios
*/
zoomScale: PropTypes.number,

/**
* When defined, displays a UIRefreshControl.
* Invoked with a function to stop refreshing when the UIRefreshControl is animating.
*
* ```
* (endRefreshing) => {
* endRefreshing();
* }
* ```
*
* @platform ios
*/
onRefreshStart: PropTypes.func,

},

mixins: [ScrollResponder.Mixin],
Expand All @@ -291,6 +307,12 @@ var ScrollView = React.createClass({
this.refs[SCROLLVIEW].setNativeProps(props);
},

endRefreshing: function() {
RCTScrollViewManager.endRefreshing(
React.findNodeHandle(this)
);
},

/**
* Returns a reference to the underlying scroll responder, which supports
* operations like `scrollTo`. All ScrollView-like components should
Expand Down Expand Up @@ -396,6 +418,13 @@ var ScrollView = React.createClass({
onResponderReject: this.scrollResponderHandleResponderReject,
};

var onRefreshStart = this.props.onRefreshStart;
// this is necessary because if we set it on props, even when empty,
// it'll trigger the default pull-to-refresh behaviour on native.
props.onRefreshStart = onRefreshStart
? function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use arrow functions instead of bind

: null;

var ScrollViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;
Expand Down
3 changes: 3 additions & 0 deletions React/Views/RCTScrollView.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
@property (nonatomic, assign) int snapToInterval;
@property (nonatomic, copy) NSString *snapToAlignment;
@property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
@property (nonatomic, copy) RCTDirectEventBlock onRefreshStart;

- (void)endRefreshing;

@end

Expand Down
38 changes: 38 additions & 0 deletions React/Views/RCTScrollView.m
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ @interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>

@property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
@property (nonatomic, assign) BOOL centerContent;
@property (nonatomic, strong) UIRefreshControl *refreshControl;

@end

Expand Down Expand Up @@ -352,6 +353,15 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
return hitView ?: [super hitTest:point withEvent:event];
}

- (void)setRefreshControl:(UIRefreshControl *)refreshControl
{
if (_refreshControl) {
[_refreshControl removeFromSuperview];
}
_refreshControl = refreshControl;
[self addSubview:_refreshControl];
}

@end

@implementation RCTScrollView
Expand Down Expand Up @@ -844,6 +854,34 @@ - (id)valueForUndefinedKey:(NSString *)key
return [_scrollView valueForKey:key];
}

- (void)setOnRefreshStart:(RCTDirectEventBlock)onRefreshStart
{
if (!onRefreshStart) {
_onRefreshStart = nil;
_scrollView.refreshControl = nil;
return;
}
_onRefreshStart = [onRefreshStart copy];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably check if onRefreshStart is nil and remove the refreshControl if it is.

Also, if onRefreshStart is not nil, and _scrollView.refreshControl is already not nil, there's no need to create and assign a new UIRefreshControl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated


if (!_scrollView.refreshControl) {
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
_scrollView.refreshControl = refreshControl;
}
}

- (void)refreshControlValueChanged
{
if (self.onRefreshStart) {
self.onRefreshStart(nil);
}
}

- (void)endRefreshing
{
[_scrollView.refreshControl endRefreshing];
}

@end

@implementation RCTEventDispatcher (RCTScrollView)
Expand Down
18 changes: 18 additions & 0 deletions React/Views/RCTScrollViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
RCT_EXPORT_VIEW_PROPERTY(snapToAlignment, NSString)
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(onRefreshStart, RCTDirectEventBlock)

- (NSDictionary<NSString *, id> *)constantsToExport
{
Expand Down Expand Up @@ -114,6 +115,22 @@ - (UIView *)view
}];
}

RCT_EXPORT_METHOD(endRefreshing:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {

RCTScrollView *view = viewRegistry[reactTag];
if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
return;
}

[view endRefreshing];

}];
}


- (NSArray<NSString *> *)customDirectEventTypes
{
return @[
Expand All @@ -127,3 +144,4 @@ - (UIView *)view
}

@end