Skip to content

refactor(scroll-view): read the offset from onScrollGeometryChange - #32

Open
romchornyi wants to merge 1 commit into
masterfrom
refactor/scroll-offset-geometry-change
Open

romchornyi wants to merge 1 commit into
masterfrom
refactor/scroll-offset-geometry-change

Conversation

@romchornyi

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Closes #25.

ScrollViewWithOnScrollChanged measured its scroll offset with a zero-size LocationReader placed as the first child of the content, inside a per-instance named coordinate space. The reason was that onScrollGeometryChange wasn't available. It is available at the iOS 18 / macOS 15 floor set by #15. The type is public API, so it stays with the same signature and is reimplemented on the system API.

What was done?

  • The offset comes from onScrollGeometryChange, computed by an internal scrollContentOrigin(of:layoutDirection:). The named coordinate space and the probe are gone.
  • The y value is unchanged. It is .zero at rest, negative while scrolled, and positive while pulled past the start.
  • x is now the real offset. Before, it was the probe's position, which was the centre of the content (for example 1230 = half the content width at rest in a horizontal view). In right-to-left layouts ScrollGeometry reports the horizontal axis differently: at rest contentOffset.x equals the trailing inset, and the leading inset does not move it. The function handles this, and tests cover it.
  • A zero-size Color.clear stays as the first child. The probe added one default stack spacing above the content, and hosts lay out against it. Removing it would move their content up.
  • The last value is sent again when the content reappears with its state kept. The probe's onAppear did the same. On first appearance exactly one value is sent.
  • LocationReader / readingLocation were internal, and the probe was their only caller, so the file is deleted. Docs and README no longer list readingLocation.
  • Previews cover vertical, vertical with a top margin, horizontal, and horizontal right-to-left.

How Has This Been Tested?

  • swift build, swift test (23 tests, 7 of them new in ScrollContentOriginTests) and xcodebuild build-for-testing for the iOS Simulator are clean.
  • Master and this branch were measured side by side on an iOS 27 simulator. A test bundle hosted the view in a UIWindow, set contentOffset on the real UIScrollView, and recorded every reported value. y is identical in every case below:
Situation master y (rest / +120 / −40) branch y
no inset 0 / −120 / 40 same
112pt top safe-area inset 0 / −120 / 40 same
safeAreaPadding(.top, 20) 0 / −120 / 40 same
ignoresSafeArea() 0 / −120 / 40 same
nested horizontal carousel scrolled 0 reports from the carousel same
large title collapsing (inset 168 → 116) −20 / −52 / −48 / −148 same
.refreshable while refreshing −60 same
content's first child at 8pt (Color first), 6.43pt (Text first) same
reappear (tab switch back) 1 re-report, current value same
  • x on the branch reads 0 at rest, goes negative towards the end, and positive past the start. That holds in LTR (with a leading or trailing inset) and in RTL (with a start inset, an end inset, or contentMargins(.horizontal, 20)), and for a vertical RTL view with horizontal margins. The unit tests use the raw ScrollGeometry values captured in those runs.
  • The only consumer, dashwallet-ios LocalCurrencyView, reads min(offset.y, 0) and uses no contentMargins, so it sees no change.

Breaking Changes

No API change: the signature is the same, and the API check covers it. The reported values change in two cases:

  • x: it is now the scroll offset instead of the content centre. Nothing reads x today.
  • contentMargins: y at rest is now 0. Before, it was the margin, because the probe sat inside the margin. With safe-area insets and safeAreaPadding, y at rest was already 0, and it still is.

Not handled and not measured, both are edge cases:

  • Layout direction flipped at runtime while the view is at rest: x updates only on the next geometry change.
  • Geometry changes while the view is hidden: on reappear the host first gets the last value seen, then the new one. Master sent only the current value.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

🤖 Generated with Claude Code

`ScrollViewWithOnScrollChanged` measured its offset with a zero-size
`LocationReader` placed as the first child of the content, inside a
per-instance named coordinate space. `onScrollGeometryChange` is
available at the iOS 18 / macOS 15 floor and reports the offset itself.

- y is the same as before at rest, while scrolled and when pulled past the
  top, under safe-area insets, `safeAreaPadding`, `ignoresSafeArea`, a
  collapsing large title and a refresh in progress.
- x now is the real offset; it used to be the probe's position, the
  centre of the content. Right-to-left layouts are handled.
- With `contentMargins`, y reads 0 at rest: the origin is measured inside
  every content inset.
- A zero-size first child stays, so content keeps the stack spacing hosts
  lay out against.
- The last value is sent again when the content reappears, as the probe's
  `onAppear` did.

`LocationReader` and `readingLocation` were internal and had no other
caller, so they go too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ScrollViewWithOnScrollChanged: move onto onScrollGeometryChange or deprecate it

1 participant