Skip to content

Commit 216606a

Browse files
committed
Fix maintainVisibleContentPosition ignoring contentInset in Fabric ScrollView
The Fabric implementation of `_adjustForMaintainVisibleContentPosition` did not account for `contentInset` when computing the autoscroll threshold comparison or the scroll target position, unlike the Paper implementation (`RCTScrollView.m`) which already handles this correctly. When a non-zero `contentInset` is set on a scroll view, two bugs occurred: 1. The threshold comparison used raw `contentOffset` instead of the inset-adjusted value, causing autoscroll to fire incorrectly. 2. The autoscroll target was hardcoded to `0` instead of `-inset`, causing the scroll view to jump to the wrong position. Fix: compute `bottomInset`/`leftInset` (respecting `isInverted`) and use them to adjust both the threshold comparison and the `scrollToOffset` target, matching the existing Paper logic in `RCTScrollView.m`. No behavior change when `contentInset` is zero.
1 parent 52d87f9 commit 216606a

1 file changed

Lines changed: 6 additions & 4 deletions

File tree

packages/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,27 +1096,29 @@ - (void)_adjustForMaintainVisibleContentPosition
10961096
if (horizontal) {
10971097
CGFloat deltaX = _firstVisibleView.frame.origin.x - _prevFirstVisibleFrame.origin.x;
10981098
if (ABS(deltaX) > 0.5) {
1099-
CGFloat x = _scrollView.contentOffset.x;
1099+
CGFloat leftInset = [self isInverted] ? _scrollView.contentInset.right : _scrollView.contentInset.left;
1100+
CGFloat x = _scrollView.contentOffset.x + leftInset;
11001101
[self _forceDispatchNextScrollEvent];
11011102
_scrollView.contentOffset = CGPointMake(_scrollView.contentOffset.x + deltaX, _scrollView.contentOffset.y);
11021103
if (autoscrollThreshold) {
11031104
// If the offset WAS within the threshold of the start, animate to the start.
11041105
if (x <= autoscrollThreshold.value()) {
1105-
[self scrollToOffset:CGPointMake(0, _scrollView.contentOffset.y) animated:YES];
1106+
[self scrollToOffset:CGPointMake(-leftInset, _scrollView.contentOffset.y) animated:YES];
11061107
}
11071108
}
11081109
}
11091110
} else {
11101111
CGRect newFrame = _firstVisibleView.frame;
11111112
CGFloat deltaY = newFrame.origin.y - _prevFirstVisibleFrame.origin.y;
11121113
if (ABS(deltaY) > 0.5) {
1113-
CGFloat y = _scrollView.contentOffset.y;
1114+
CGFloat bottomInset = [self isInverted] ? _scrollView.contentInset.top : _scrollView.contentInset.bottom;
1115+
CGFloat y = _scrollView.contentOffset.y + bottomInset;
11141116
[self _forceDispatchNextScrollEvent];
11151117
_scrollView.contentOffset = CGPointMake(_scrollView.contentOffset.x, _scrollView.contentOffset.y + deltaY);
11161118
if (autoscrollThreshold) {
11171119
// If the offset WAS within the threshold of the start, animate to the start.
11181120
if (y <= autoscrollThreshold.value()) {
1119-
[self scrollToOffset:CGPointMake(_scrollView.contentOffset.x, 0) animated:YES];
1121+
[self scrollToOffset:CGPointMake(_scrollView.contentOffset.x, -bottomInset) animated:YES];
11201122
}
11211123
}
11221124
}

0 commit comments

Comments
 (0)