Skip to content

Commit

Permalink
Allows RefreshControl to be mounted with refreshing = true
Browse files Browse the repository at this point in the history
Summary:
RefreshControl did not start refreshing when refreshing was set to true initially. It also did not start refreshing on iOS when setting the prop from false to true without doing a pull to refresh gesture.

This was a pain in the ass to make work on iOS because UIRefreshControl seems super sensitive to when beginRefreshing can be called, for the initial render I need to call it in layoutSubviews. I also have to manually adjust the scrollview content offset when calling beginRefreshing. The code is a bit hacky but it was the only solution I found that was actually working.

Fixes #5716
Closes #5745

Reviewed By: svcscm

Differential Revision: D2910716

Pulled By: nicklockwood

fb-gh-sync-id: d60e73bcfe8d86bb01249ba5f17e6a23c5a5aff6
  • Loading branch information
janicduplessis authored and facebook-github-bot-5 committed Feb 7, 2016
1 parent 7b22606 commit 3e1f1ea
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
53 changes: 50 additions & 3 deletions React/Views/RCTRefreshControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,59 @@

#import "RCTUtils.h"

@implementation RCTRefreshControl
@implementation RCTRefreshControl {
BOOL _initialRefreshingState;
BOOL _isInitialRender;
}

- (instancetype)init
{
if ((self = [super init])) {
[self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
_isInitialRender = true;
}
return self;
}

RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)

- (void)layoutSubviews
{
[super layoutSubviews];

// If the control is refreshing when mounted we need to call
// beginRefreshing in layoutSubview or it doesn't work.
if (_isInitialRender && _initialRefreshingState) {
[self beginRefreshing];
}
_isInitialRender = false;
}

- (void)beginRefreshing
{
// When using begin refreshing we need to adjust the ScrollView content offset manually.
UIScrollView *scrollView = (UIScrollView *)self.superview;
CGPoint offset = {scrollView.contentOffset.x, scrollView.contentOffset.y - self.frame.size.height};
// Don't animate when the prop is set initialy.
if (_isInitialRender) {
// Must use `[scrollView setContentOffset:offset animated:NO]` instead of just setting
// `scrollview.contentOffset` or it doesn't work, don't ask me why!
[scrollView setContentOffset:offset animated:NO];
[super beginRefreshing];
} else {
// `beginRefreshing` must be called after the animation is done. This is why it is impossible
// to use `setContentOffset` with `animated:YES`.
[UIView animateWithDuration:0.25
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^(void) {
[scrollView setContentOffset:offset];
} completion:^(__unused BOOL finished) {
[super beginRefreshing];
}];
}
}

- (NSString *)title
{
return self.attributedTitle.string;
Expand All @@ -35,9 +76,15 @@ - (void)setTitle:(NSString *)title

- (void)setRefreshing:(BOOL)refreshing
{
if (super.refreshing != refreshing) {
if (self.refreshing != refreshing) {
if (refreshing) {
[self beginRefreshing];
// If it is the initial render, beginRefreshing will get called
// in layoutSubviews.
if (_isInitialRender) {
_initialRefreshingState = refreshing;
} else {
[self beginRefreshing];
}
} else {
[self endRefreshing];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ public void setSize(ReactSwipeRefreshLayout view, int size) {
}

@ReactProp(name = "refreshing")
public void setRefreshing(ReactSwipeRefreshLayout view, boolean refreshing) {
view.setRefreshing(refreshing);
public void setRefreshing(final ReactSwipeRefreshLayout view, final boolean refreshing) {
// Use `post` otherwise the control won't start refreshing if refreshing is true when
// the component gets mounted.
view.post(new Runnable() {
@Override
public void run() {
view.setRefreshing(refreshing);
}
});
}

@Override
Expand Down

0 comments on commit 3e1f1ea

Please sign in to comment.