Skip to content

Commit dd6f7cc

Browse files
committed
Implement ScrollViewProviding
1 parent 4257056 commit dd6f7cc

11 files changed

+84
-42
lines changed

ios/RNSScreen.mm

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,8 +1242,9 @@ - (void)overrideScrollViewBehaviorInFirstDescendantChainIfNeeded
12421242

12431243
- (void)updateContentScrollViewEdgeEffectsIfExists
12441244
{
1245-
[RNSScrollEdgeEffectApplicator applyToScrollView:[RNSScrollViewFinder findScrollViewInFirstDescendantChainFrom:self]
1246-
withProvider:self];
1245+
[RNSScrollEdgeEffectApplicator
1246+
applyToScrollView:[RNSScrollViewFinder findContentScrollViewWithFirstDescendantsChain:self]
1247+
withProvider:self];
12471248
}
12481249

12491250
#pragma mark - RNSSafeAreaProviding

ios/RNSScreenStack.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ - (bool)onRepeatedTabSelectionOfTabScreenController:(RNSTabsScreenViewController
194194
return [[self popToRootViewControllerAnimated:true] count] > 0;
195195
} else if (tabScreenController.tabScreenComponentView.shouldUseRepeatedTabSelectionScrollToTopSpecialEffect) {
196196
UIScrollView *scrollView =
197-
[RNSScrollViewFinder findScrollViewInFirstDescendantChainFrom:[[self topViewController] view]];
197+
[RNSScrollViewFinder findContentScrollViewWithFirstDescendantsChain:[[self topViewController] view]];
198198
return [scrollView rnscreens_scrollToTop];
199199
}
200200

ios/RNSScrollViewFinder.h

Lines changed: 0 additions & 13 deletions
This file was deleted.

ios/RNSScrollViewFinder.mm

Lines changed: 0 additions & 22 deletions
This file was deleted.

ios/bottom-tabs/RNSBottomTabsScreenComponentView.mm

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ - (void)overrideScrollViewBehaviorInFirstDescendantChainIfNeeded
165165

166166
- (void)updateContentScrollViewEdgeEffectsIfExists
167167
{
168-
[RNSScrollEdgeEffectApplicator applyToScrollView:[RNSScrollViewFinder findScrollViewInFirstDescendantChainFrom:self]
169-
withProvider:self];
168+
[RNSScrollEdgeEffectApplicator
169+
applyToScrollView:[RNSScrollViewFinder findContentScrollViewWithFirstDescendantsChain:self]
170+
withProvider:self];
170171
}
171172

172173
#pragma mark - Prop update utils

ios/bottom-tabs/RNSTabsScreenViewController.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ - (bool)tabScreenSelectedRepeatedly
107107
return [[self tabsSpecialEffectsDelegate] onRepeatedTabSelectionOfTabScreenController:self];
108108
} else if (self.tabScreenComponentView.shouldUseRepeatedTabSelectionScrollToTopSpecialEffect) {
109109
UIScrollView *scrollView =
110-
[RNSScrollViewFinder findScrollViewInFirstDescendantChainFrom:[self tabScreenComponentView]];
110+
[RNSScrollViewFinder findContentScrollViewWithFirstDescendantsChain:[self tabScreenComponentView]];
111111
return [scrollView rnscreens_scrollToTop];
112112
}
113113

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@protocol RNSContentScrollViewProviding
2+
/**
3+
* Finds content ScrollView within provider's hierarchy. The content ScrollView serves as a main interaction on the
4+
* given screen. Implementations should use `RNSScrollViewFinder.findContentScrollViewWithDelegatingToProvider` to
5+
* continue continue the search when no more custom logic is necessary (e.g Stack determining the topmost screen (custom
6+
* part) and forwarding the call directly to its view (going back to regular search)).
7+
*/
8+
- (nullable UIScrollView *)findContentScrollView;
9+
@end
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#import <UIKit/UIKit.h>
2+
#import "RNSContentScrollViewProviding.h"
3+
4+
@interface RNSScrollViewFinder : NSObject
5+
/**
6+
* Searches for content ScrollView by traversing down the hierarchy using first subview, similar to UIKit behavior.
7+
* It will fail if:
8+
* - UIScrollView is not a first subview of view or one of its descendants in the hierarchy,
9+
* - if UIScrollView's parent is not yet attached.
10+
*/
11+
+ (nullable UIScrollView *)findContentScrollViewWithFirstDescendantsChain:(nullable UIView *)view;
12+
13+
/**
14+
* Looks for UIScrollView in a similar way to `findContentScrollViewWithFirstDescendantsChain`, until it finds
15+
* `RNSContentScrollViewProviding`. Then, it delegates the task to the provider, and returns the results. This can
16+
* overcome the problems of subviews' children not being mounted yet, or ScrollView being mounted at index different
17+
* than 0.
18+
*
19+
* Caveat: when traversing the hierarchy, we don't check for conformance to protocol,
20+
* but whether the view responds to `RNSContentScrollViewProviding.findContentScrollView`.
21+
* This doesn't place locks and is faster.
22+
*/
23+
+ (nullable UIScrollView *)findContentScrollViewWithDelegatingToProvider:(nullable UIView *)view;
24+
25+
@end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#import "RNSScrollViewFinder.h"
2+
3+
@implementation RNSScrollViewFinder
4+
5+
+ (UIScrollView *)findContentScrollViewWithFirstDescendantsChain:(UIView *)view
6+
{
7+
UIView *currentView = view;
8+
9+
while (currentView != nil) {
10+
if ([currentView isKindOfClass:UIScrollView.class]) {
11+
return static_cast<UIScrollView *>(currentView);
12+
} else if ([currentView.subviews count] > 0) {
13+
currentView = currentView.subviews[0];
14+
} else {
15+
break;
16+
}
17+
}
18+
19+
return nil;
20+
}
21+
22+
+ (nullable UIScrollView *)findContentScrollViewWithDelegatingToProvider:(nullable UIView *)view
23+
{
24+
UIView *currentView = view;
25+
26+
while (currentView != nil) {
27+
if ([currentView isKindOfClass:UIScrollView.class]) {
28+
return static_cast<UIScrollView *>(currentView);
29+
} else if ([currentView respondsToSelector:@selector(findContentScrollView)]) {
30+
return [static_cast<id<RNSContentScrollViewProviding>>(currentView) findContentScrollView];
31+
} else if ([currentView.subviews count] > 0) {
32+
currentView = currentView.subviews[0];
33+
} else {
34+
break;
35+
}
36+
}
37+
38+
return nil;
39+
}
40+
41+
@end
File renamed without changes.

0 commit comments

Comments
 (0)