Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ios/RNSScreen.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1242,8 +1242,9 @@ - (void)overrideScrollViewBehaviorInFirstDescendantChainIfNeeded

- (void)updateContentScrollViewEdgeEffectsIfExists
{
[RNSScrollEdgeEffectApplicator applyToScrollView:[RNSScrollViewFinder findScrollViewInFirstDescendantChainFrom:self]
withProvider:self];
[RNSScrollEdgeEffectApplicator
applyToScrollView:[RNSScrollViewFinder findContentScrollViewWithDelegatingToProvider:self]
withProvider:self];
}

#pragma mark - RNSSafeAreaProviding
Expand Down
13 changes: 0 additions & 13 deletions ios/RNSScrollViewFinder.h

This file was deleted.

22 changes: 0 additions & 22 deletions ios/RNSScrollViewFinder.mm

This file was deleted.

2 changes: 2 additions & 0 deletions ios/bottom-tabs/RNSBottomTabsHostComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import "RNSEnums.h"
#import "RNSReactBaseView.h"
#import "RNSScreenContainer.h"
#import "RNSScrollViewFinder.h"

#ifdef RCT_NEW_ARCH_ENABLED
#import "RNSViewControllerInvalidating.h"
Expand All @@ -27,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface RNSBottomTabsHostComponentView : RNSReactBaseView <
RNSScreenContainerDelegate,
RNSContentScrollViewProviding,
#ifdef RCT_NEW_ARCH_ENABLED
RNSViewControllerInvalidating
#else
Expand Down
19 changes: 19 additions & 0 deletions ios/bottom-tabs/RNSBottomTabsHostComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ - (void)invalidate

#endif

#pragma mark - RNSContentScrollViewProviding

- (UIScrollView *)findContentScrollView
{
#if !TARGET_OS_TV && !TARGET_OS_VISION
if (_controller.selectedViewController == _controller.moreNavigationController) {
// Logic for More Controller; user is shown the native list of tabs.
// This we want to keep as-is, we're not styling the ScrollView here,
// so let's pretend there isn't one
return nil;
}
#endif // check for build target != tvOS, visionOS

// User selected regular tab with our BottomTabScreenComponentView. We start directly from it.
// This has the advantage of being able to continue searching even if the TabScreen
// hasn't been mounted yet (see mountChildComponentView(), _reactSubviews).
return [RNSScrollViewFinder findContentScrollViewWithDelegatingToProvider:_controller.selectedViewController.view];
}

#pragma mark - React events

- (nonnull RNSBottomTabsHostEventEmitter *)reactEventEmitter
Expand Down
9 changes: 9 additions & 0 deletions ios/helpers/scroll-view/RNSContentScrollViewProviding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@protocol RNSContentScrollViewProviding

/**
* Finds content ScrollView within provider's hierarchy. The content ScrollView serves as a main interaction on the
* given screen. Implementations may use `RNSScrollViewFinder` to continue the search however they see fit.
*/
- (nullable UIScrollView *)findContentScrollView;

@end
26 changes: 26 additions & 0 deletions ios/helpers/scroll-view/RNSScrollViewFinder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#import <UIKit/UIKit.h>
#import "RNSContentScrollViewProviding.h"

@interface RNSScrollViewFinder : NSObject

/**
* Searches for content ScrollView by traversing down the hierarchy using first subview, similar to UIKit behavior.
* It will fail if:
* - UIScrollView is not a first subview of view or one of its descendants in the hierarchy,
* - if UIScrollView's parent is not yet attached.
*
* When `view == nil`, it should also return `nil`.
*/
+ (nullable UIScrollView *)findScrollViewInFirstDescendantChainFrom:(nullable UIView *)view;

/**
* Looks for UIScrollView in a similar way to `findScrollViewInFirstDescendantChainFrom`, until it finds
* `RNSContentScrollViewProviding`. Then, it delegates the task to the provider, and returns the results. This can
* overcome the problems of subviews' children not being mounted yet, or ScrollView being mounted at index different
* than 0.
*
* When `view == nil`, it should also return `nil`.
*/
+ (nullable UIScrollView *)findContentScrollViewWithDelegatingToProvider:(nullable UIView *)view;

@end
44 changes: 44 additions & 0 deletions ios/helpers/scroll-view/RNSScrollViewFinder.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#import "RNSScrollViewFinder.h"

@implementation RNSScrollViewFinder

+ (UIScrollView *)findScrollViewInFirstDescendantChainFrom:(UIView *)view
{
UIView *currentView = view;

while (currentView != nil) {
if ([currentView isKindOfClass:UIScrollView.class]) {
return static_cast<UIScrollView *>(currentView);
} else if ([currentView.subviews count] > 0) {
currentView = currentView.subviews[0];
} else {
break;
}
}

return nil;
}

+ (nullable UIScrollView *)findContentScrollViewWithDelegatingToProvider:(nullable UIView *)view
{
UIView *currentView = view;

while (currentView != nil) {
if ([currentView isKindOfClass:UIScrollView.class]) {
return static_cast<UIScrollView *>(currentView);
} else if ([currentView respondsToSelector:@selector(findContentScrollView)]) {
// When traversing the hierarchy, we don't check for conformance to protocol,
// but whether the view responds to `RNSContentScrollViewProviding.findContentScrollView`.
// This doesn't place locks and is faster.
return [static_cast<id<RNSContentScrollViewProviding>>(currentView) findContentScrollView];
} else if ([currentView.subviews count] > 0) {
currentView = currentView.subviews[0];
} else {
break;
}
}

return nil;
}

@end
File renamed without changes.
Loading