Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) BOOL snapToEnd;
@property (nonatomic, copy) NSArray<NSNumber *> *snapToOffsets;

/*
* Whether this scroll view is mirrored by a `scaleY(-1)` transform, as inverted virtualized lists
* are. UIKit does not account for that transform when it positions iOS 26 scroll edge effects, so
* they have to be compensated for here.
*/
@property (nonatomic, assign) BOOL inverted;

/*
* Makes `setContentOffset:` method no-op when given `block` is executed.
* The block is being executed synchronously.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ - (instancetype)initWithFrame:(CGRect)frame
return self;
}

- (void)setInverted:(BOOL)inverted
{
if (_inverted == inverted) {
return;
}
_inverted = inverted;

if (@available(iOS 26.0, *)) {
// UIKit positions the scroll edge effects in this scroll view's own coordinate space, and the
// `scaleY(-1)` mirror turns that space upside down, so neither effect lands where it belongs.
// Against a navigation bar, `topEdgeEffect` darkens the lower half of the screen rather than
// the content passing under the bar; against a bottom bar, `bottomEdgeEffect` dims the whole
// screen. Neither produces anything useful at any scroll position while mirrored, so both are
// hidden. The bars cannot be given correct effects from here, because UIKit has no notion of
// the transform.
self.topEdgeEffect.hidden = inverted;
self.bottomEdgeEffect.hidden = inverted;
}
}

- (void)preserveContentOffsetWithBlock:(void (^)())block
{
if (!block) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
}

[super updateProps:props oldProps:oldProps];

// Must run after `super updateProps:` so it is based on the latest calculated view.
((RCTEnhancedScrollView *)_scrollView).inverted = [self isInverted];
}

- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ interface RCTDivisionAnimatedNode : public RCTValueAnimatedNode {
interface RCTEnhancedScrollView : public UIScrollView {
public @property (assign) BOOL centerContent;
public @property (assign) BOOL disableIntervalMomentum;
public @property (assign) BOOL inverted;
public @property (assign) BOOL pinchGestureEnabled;
public @property (assign) BOOL snapToEnd;
public @property (assign) BOOL snapToStart;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ interface RCTDivisionAnimatedNode : public RCTValueAnimatedNode {
interface RCTEnhancedScrollView : public UIScrollView {
public @property (assign) BOOL centerContent;
public @property (assign) BOOL disableIntervalMomentum;
public @property (assign) BOOL inverted;
public @property (assign) BOOL pinchGestureEnabled;
public @property (assign) BOOL snapToEnd;
public @property (assign) BOOL snapToStart;
Expand Down
1 change: 1 addition & 0 deletions scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ interface RCTDivisionAnimatedNode : public RCTValueAnimatedNode {
interface RCTEnhancedScrollView : public UIScrollView {
public @property (assign) BOOL centerContent;
public @property (assign) BOOL disableIntervalMomentum;
public @property (assign) BOOL inverted;
public @property (assign) BOOL pinchGestureEnabled;
public @property (assign) BOOL snapToEnd;
public @property (assign) BOOL snapToStart;
Expand Down
Loading