mirror of
https://github.com/status-im/react-native.git
synced 2025-01-17 21:11:45 +00:00
102a31c13e
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
120 lines
3.4 KiB
Objective-C
120 lines
3.4 KiB
Objective-C
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "RCTRefreshControl.h"
|
|
|
|
#import "RCTUtils.h"
|
|
|
|
@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) {
|
|
scrollView.contentOffset = offset;
|
|
[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];
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
|
|
- (void)setTitle:(NSString *)title
|
|
{
|
|
self.attributedTitle = [[NSAttributedString alloc] initWithString:title];
|
|
}
|
|
|
|
- (void)setRefreshing:(BOOL)refreshing
|
|
{
|
|
if (self.refreshing != refreshing) {
|
|
if (refreshing) {
|
|
// If it is the initial render, beginRefreshing will get called
|
|
// in layoutSubviews.
|
|
if (_isInitialRender) {
|
|
_initialRefreshingState = refreshing;
|
|
} else {
|
|
[self beginRefreshing];
|
|
}
|
|
} else {
|
|
[self endRefreshing];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)refreshControlValueChanged
|
|
{
|
|
if (_onRefresh) {
|
|
_onRefresh(nil);
|
|
}
|
|
}
|
|
|
|
@end
|