UIRefreshControl added to scroll view

Summary: **What:**

adds `onRefreshStart` property to `ScrollView.js` for displaying and activating pull to refresh.

**Why:**

Javascript implementations seemed a little flakey and inconsistent.  As you can see in the issues below:

https://github.com/facebook/react-native/issues/2356
https://github.com/facebook/react-native/issues/745

So this is an attempt a completely native implementation.

What do you think?

![Image of dog](http://i.imgur.com/HcTQnzJ.gif)
Closes https://github.com/facebook/react-native/pull/4205

Reviewed By: svcscm

Differential Revision: D2674945

Pulled By: nicklockwood

fb-gh-sync-id: 65113a5db9785df5a95c68323c2cdf19f3b217b1
This commit is contained in:
EwanThomas 2015-11-19 11:13:42 -08:00 коммит произвёл facebook-github-bot-4
Родитель 5950f8cf15
Коммит 2faf8632d3
4 изменённых файлов: 88 добавлений и 0 удалений

Просмотреть файл

@ -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;
@ -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],
@ -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
@ -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)
: null;
var ScrollViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;

Просмотреть файл

@ -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

Просмотреть файл

@ -144,6 +144,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
@property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
@property (nonatomic, assign) BOOL centerContent;
@property (nonatomic, strong) UIRefreshControl *refreshControl;
@end
@ -352,6 +353,15 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return hitView ?: [super hitTest:point withEvent:event];
}
- (void)setRefreshControl:(UIRefreshControl *)refreshControl
{
if (_refreshControl) {
[_refreshControl removeFromSuperview];
}
_refreshControl = refreshControl;
[self addSubview:_refreshControl];
}
@end
@implementation RCTScrollView
@ -844,6 +854,34 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, UIEdgeInsets);
return [_scrollView valueForKey:key];
}
- (void)setOnRefreshStart:(RCTDirectEventBlock)onRefreshStart
{
if (!onRefreshStart) {
_onRefreshStart = nil;
_scrollView.refreshControl = nil;
return;
}
_onRefreshStart = [onRefreshStart copy];
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)

Просмотреть файл

@ -65,6 +65,7 @@ RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
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
{
@ -114,6 +115,22 @@ RCT_EXPORT_METHOD(calculateChildFrames:(nonnull NSNumber *)reactTag
}];
}
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 @[
@ -127,3 +144,4 @@ RCT_EXPORT_METHOD(calculateChildFrames:(nonnull NSNumber *)reactTag
}
@end