Skip to content

Commit

Permalink
Add fix for refresh control state's race condition. (#21763)
Browse files Browse the repository at this point in the history
Summary:
Fixes #21762
Pull Request resolved: #21763

Differential Revision: D14064621

Pulled By: cpojer

fbshipit-source-id: 63010248a46cb49ed17ed89d7c55945aa7b22973
  • Loading branch information
rostislav-simonik authored and facebook-github-bot committed Feb 15, 2019
1 parent e5fbd39 commit 95d399b
Showing 1 changed file with 22 additions and 4 deletions.
26 changes: 22 additions & 4 deletions React/Views/RCTRefreshControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
@implementation RCTRefreshControl {
BOOL _isInitialRender;
BOOL _currentRefreshingState;
UInt64 _currentRefreshingStateClock;
UInt64 _currentRefreshingStateTimestamp;
BOOL _refreshingProgrammatically;
NSString *_title;
UIColor *_titleColor;
Expand All @@ -21,6 +23,8 @@ - (instancetype)init
{
if ((self = [super init])) {
[self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
_currentRefreshingStateClock = 1;
_currentRefreshingStateTimestamp = 0;
_isInitialRender = true;
_currentRefreshingState = false;
}
Expand Down Expand Up @@ -49,6 +53,7 @@ - (void)layoutSubviews

- (void)beginRefreshingProgrammatically
{
UInt64 beginRefreshingTimestamp = _currentRefreshingStateTimestamp;
_refreshingProgrammatically = YES;
// When using begin refreshing we need to adjust the ScrollView content offset manually.
UIScrollView *scrollView = (UIScrollView *)self.superview;
Expand All @@ -62,7 +67,10 @@ - (void)beginRefreshingProgrammatically
animations:^(void) {
[scrollView setContentOffset:offset];
} completion:^(__unused BOOL finished) {
[super beginRefreshing];
if(beginRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
[super beginRefreshing];
[self setCurrentRefreshingState:super.refreshing];
}
}];
}

Expand All @@ -72,14 +80,18 @@ - (void)endRefreshingProgrammatically
// endRefreshing otherwise the next pull to refresh will not work properly.
UIScrollView *scrollView = (UIScrollView *)self.superview;
if (_refreshingProgrammatically && scrollView.contentOffset.y < 0) {
UInt64 endRefreshingTimestamp = _currentRefreshingStateTimestamp;
CGPoint offset = {scrollView.contentOffset.x, 0};
[UIView animateWithDuration:0.25
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^(void) {
[scrollView setContentOffset:offset];
} completion:^(__unused BOOL finished) {
[super endRefreshing];
if(endRefreshingTimestamp == self->_currentRefreshingStateTimestamp) {
[super endRefreshing];
[self setCurrentRefreshingState:super.refreshing];
}
}];
} else {
[super endRefreshing];
Expand Down Expand Up @@ -120,7 +132,7 @@ - (void)_updateTitle
- (void)setRefreshing:(BOOL)refreshing
{
if (_currentRefreshingState != refreshing) {
_currentRefreshingState = refreshing;
[self setCurrentRefreshingState:refreshing];

if (refreshing) {
if (!_isInitialRender) {
Expand All @@ -132,9 +144,15 @@ - (void)setRefreshing:(BOOL)refreshing
}
}

- (void)setCurrentRefreshingState:(BOOL)refreshing
{
_currentRefreshingState = refreshing;
_currentRefreshingStateTimestamp = _currentRefreshingStateClock++;
}

- (void)refreshControlValueChanged
{
_currentRefreshingState = super.refreshing;
[self setCurrentRefreshingState:super.refreshing];
_refreshingProgrammatically = NO;

if (_onRefresh) {
Expand Down

0 comments on commit 95d399b

Please sign in to comment.