From 102a31c13eed82432b3e0d93230653394f7baa3d Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 8 Mar 2016 04:00:02 -0800 Subject: [PATCH] Fix RefreshControl layout on screen rotation and consecutive pull to refresh not working properly Summary:Fixes the RefreshControl layout after a screen rotation. See #6311 for a more detailed explanation. I fixed it by adjusting the frame of the RefreshControl in `layoutSubviews` of the parent ScrollView. While working on fixing this I noticed that when doing a 'pull to refresh' and then not scrolling and wait for it to end the next one will not behave like the first one (it will require pulling further down for the spinner to start spinning). I fixed that too by scrolling the scrollview back to 0 manually before calling `UIRefreshControl.endRefreshing`. **Test plan (required)** Tested using the UIExplorer RefreshControl example. When doing a pull to refresh and then rotating the screen the RefreshControl must stay positioned properly. Doing multiple consecutive pull to refresh without scrolling after should all behave the same. Fixes #6311 Closes https://github.com/facebook/react-native/pull/6359 Differential Revision: D3023727 fb-gh-sync-id: f50ae52ea769c2b3e5025c362544a8809a71aa00 shipit-source-id: f50ae52ea769c2b3e5025c362544a8809a71aa00 --- React/Views/RCTRefreshControl.m | 20 ++++++++++++++++++++ React/Views/RCTScrollView.m | 6 ++++++ 2 files changed, 26 insertions(+) diff --git a/React/Views/RCTRefreshControl.m b/React/Views/RCTRefreshControl.m index 282cd7f30308c8..5d24ffadc7d113 100644 --- a/React/Views/RCTRefreshControl.m +++ b/React/Views/RCTRefreshControl.m @@ -62,6 +62,26 @@ - (void)beginRefreshing } } +- (void)endRefreshing +{ + // The contentOffset of the scrollview MUST be greater than 0 before calling + // endRefreshing otherwise the next pull to refresh will not work properly. + UIScrollView *scrollView = (UIScrollView *)self.superview; + if (scrollView.contentOffset.y < 0) { + 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]; + }]; + } else { + [super endRefreshing]; + } +} + - (NSString *)title { return self.attributedTitle.string; diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m index af0091e03a71e0..1a3f0b0183f639 100644 --- a/React/Views/RCTScrollView.m +++ b/React/Views/RCTScrollView.m @@ -495,6 +495,12 @@ - (void)layoutSubviews _scrollView.frame = self.bounds; _scrollView.contentOffset = originalOffset; + // Adjust the refresh control frame if the scrollview layout changes. + RCTRefreshControl *refreshControl = _scrollView.refreshControl; + if (refreshControl && refreshControl.refreshing) { + refreshControl.frame = (CGRect){_scrollView.contentOffset, {_scrollView.frame.size.width, refreshControl.frame.size.height}}; + } + [self updateClippedSubviews]; }