Skip to content

Commit fab5fff

Browse files
Peter Arganyfacebook-github-bot
Peter Argany
authored andcommitted
Fixed OSS scroll view bug caused by FBPullToRefresh
Summary: When I bridged FBPullToRefresh to RN, the integration with ScrollView caused a bug on OSS TLDR; assuming that a scrollview subview that implemented UIScrollViewDelegate protocol was a custom PTR was a bad idea. This caused some scrollviews to break in OSS. The solution is to define a more explicit protocol. Further details here: #20324 Reviewed By: mmmulani Differential Revision: D8953893 fbshipit-source-id: 98cdc7fcced41d9e98e77293a03934f10c798665
1 parent 1f54574 commit fab5fff

File tree

3 files changed

+33
-21
lines changed

3 files changed

+33
-21
lines changed

React/Views/RCTRefreshControl.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
#import <UIKit/UIKit.h>
99

1010
#import <React/RCTComponent.h>
11+
#import <React/RCTScrollableProtocol.h>
1112

12-
@interface RCTRefreshControl : UIRefreshControl
13+
@interface RCTRefreshControl : UIRefreshControl <RCTCustomRefreshContolProtocol>
1314

1415
@property (nonatomic, copy) NSString *title;
1516
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;

React/Views/ScrollView/RCTScrollView.m

+20-20
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ @interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>
155155

156156
@property (nonatomic, assign) BOOL centerContent;
157157
#if !TARGET_OS_TV
158-
@property (nonatomic, strong) RCTRefreshControl *rctRefreshControl;
158+
@property (nonatomic, strong) UIView<RCTCustomRefreshContolProtocol> *customRefreshControl;
159159
@property (nonatomic, assign) BOOL pinchGestureEnabled;
160160
#endif
161161

@@ -329,13 +329,13 @@ - (void)setFrame:(CGRect)frame
329329
}
330330

331331
#if !TARGET_OS_TV
332-
- (void)setRctRefreshControl:(RCTRefreshControl *)refreshControl
332+
- (void)setCustomRefreshControl:(UIView<RCTCustomRefreshContolProtocol> *)refreshControl
333333
{
334-
if (_rctRefreshControl) {
335-
[_rctRefreshControl removeFromSuperview];
334+
if (_customRefreshControl) {
335+
[_customRefreshControl removeFromSuperview];
336336
}
337-
_rctRefreshControl = refreshControl;
338-
[self addSubview:_rctRefreshControl];
337+
_customRefreshControl = refreshControl;
338+
[self addSubview:_customRefreshControl];
339339
}
340340

341341
- (void)setPinchGestureEnabled:(BOOL)pinchGestureEnabled
@@ -443,13 +443,12 @@ - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
443443
{
444444
[super insertReactSubview:view atIndex:atIndex];
445445
#if !TARGET_OS_TV
446-
if ([view isKindOfClass:[RCTRefreshControl class]]) {
447-
[_scrollView setRctRefreshControl:(RCTRefreshControl *)view];
448-
}
449-
else if ([view conformsToProtocol:@protocol(UIScrollViewDelegate)]) {
450-
[self addScrollListener:(UIView<UIScrollViewDelegate> *)view];
451-
[_scrollView addSubview:view];
452-
[_scrollView sendSubviewToBack:view];
446+
if ([view conformsToProtocol:@protocol(RCTCustomRefreshContolProtocol)]) {
447+
[_scrollView setCustomRefreshControl:(UIView<RCTCustomRefreshContolProtocol> *)view];
448+
if (![view isKindOfClass:[UIRefreshControl class]]
449+
&& [view conformsToProtocol:@protocol(UIScrollViewDelegate)]) {
450+
[self addScrollListener:(UIView<UIScrollViewDelegate> *)view];
451+
}
453452
} else
454453
#endif
455454
{
@@ -464,11 +463,12 @@ - (void)removeReactSubview:(UIView *)subview
464463
{
465464
[super removeReactSubview:subview];
466465
#if !TARGET_OS_TV
467-
if ([subview isKindOfClass:[RCTRefreshControl class]]) {
468-
[_scrollView setRctRefreshControl:nil];
469-
} else if ([subview conformsToProtocol:@protocol(UIScrollViewDelegate)]) {
470-
[self removeScrollListener:(UIView<UIScrollViewDelegate> *)subview];
471-
[subview removeFromSuperview];
466+
if ([subview conformsToProtocol:@protocol(RCTCustomRefreshContolProtocol)]) {
467+
[_scrollView setCustomRefreshControl:nil];
468+
if (![subview isKindOfClass:[UIRefreshControl class]]
469+
&& [subview conformsToProtocol:@protocol(UIScrollViewDelegate)]) {
470+
[self removeScrollListener:(UIView<UIScrollViewDelegate> *)subview];
471+
}
472472
} else
473473
#endif
474474
{
@@ -519,8 +519,8 @@ - (void)layoutSubviews
519519

520520
#if !TARGET_OS_TV
521521
// Adjust the refresh control frame if the scrollview layout changes.
522-
RCTRefreshControl *refreshControl = _scrollView.rctRefreshControl;
523-
if (refreshControl && refreshControl.refreshing) {
522+
UIView<RCTCustomRefreshContolProtocol> *refreshControl = _scrollView.customRefreshControl;
523+
if (refreshControl && refreshControl.isRefreshing) {
524524
refreshControl.frame = (CGRect){_scrollView.contentOffset, {_scrollView.frame.size.width, refreshControl.frame.size.height}};
525525
}
526526
#endif

React/Views/ScrollView/RCTScrollableProtocol.h

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#import <UIKit/UIKit.h>
9+
#import <React/RCTComponent.h>
910

1011
/**
1112
* Contains any methods related to scrolling. Any `RCTView` that has scrolling
@@ -28,3 +29,13 @@
2829
- (void)removeScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener;
2930

3031
@end
32+
33+
/**
34+
* Denotes a view which implements custom pull to refresh functionality.
35+
*/
36+
@protocol RCTCustomRefreshContolProtocol
37+
38+
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
39+
@property (nonatomic, readonly, getter=isRefreshing) BOOL refreshing;
40+
41+
@end

0 commit comments

Comments
 (0)