Skip to content

[Fabric] Implement snapToInterval property for ScrollView #14847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 15, 2025

Conversation

anupriya13
Copy link
Contributor

@anupriya13 anupriya13 commented Jul 8, 2025

Description

Type of Change

  • New feature (non-breaking change which adds functionality)

Why

Implement snapToInterval property for ScrollView in Fabric

Resolves #13150

What

https://reactnative.dev/docs/scrollview#snaptointerval
image

The snapToInterval property was available in the Paper implementation via ScrollViewManager.cpp but was missing from the Fabric implementation in ScrollViewComponentView.cpp. This meant that developers using the new architecture couldn't use interval-based snapping behavior.

Refer IOS https://github.com/facebook/react-native/blob/618279508159191f2b11c0b20446f91e82a27abf/packages/react-native/React/Views/ScrollView/RCTScrollView.m#L810C5-L813C8

Solution

Added comprehensive support for snapToInterval that:

  1. Detects property changes: Modified updateProps() to check for snapToInterval changes alongside existing snap properties
  2. Generates snap points: Created updateSnapPoints() helper method that converts interval values to discrete snap point offsets
  3. Handles content changes: Modified updateContentVisualSize() to recalculate snap points when content size changes
  4. Respects priority: Follows React Native behavior where snapToOffsets takes priority over snapToInterval

Implementation Details

updateSnapPoints() function sets up where the scroll view should snap when scrolling stops. It first checks if explicit snap positions (snapToOffsets) are provided and uses them. If not, and a snap interval is set (snapToInterval), it generates evenly spaced snap points across the content size. Finally, it updates the scroll visual to use these snap points.

// Property priority (matches React Native behavior)
if (viewProps.snapToOffsets.size() > 0) {
  // Use explicit snapToOffsets
} else if (viewProps.snapToInterval > 0) {
  // Generate snap points at regular intervals
  float interval = viewProps.snapToInterval * pointScaleFactor;
  for (float offset = 0; offset <= contentLength; offset += interval) {
    snapToOffsets.Append(offset);
  }
}

Step by Step:

✅ 1. Get the snap configuration from props

snapToOffsets: a list of exact positions to snap to

snapToInterval: a distance between each snap point

horizontal: whether the scroll is sideways

✅ 2. Decide which to use:

If snapToOffsets is provided and has items, it takes priority.

If not, but snapToInterval > 0, it generates snap points by repeating the interval.

✅ 3. Calculate how big the scrollable content is:

If horizontal, use the content width.

If vertical, use the content height.

Multiply by pointScaleFactor (to handle screen scaling).

✅ 4. Create snap points every interval distance:

For example, every 100 pixels, 200 pixels, etc.

Stop when you reach the end of content or hit a safety limit (max 1000 snap points).

✅ 5. Save the snap points in m_scrollVisual:

These will be used when scrolling stops to snap to the nearest position.

Testing

Playground tested

Changelog

Should this change be included in the release notes: yes

Add a brief summary of the change to use in the release notes for the next release.
Implement snapToInterval property for ScrollView in Fabric

Microsoft Reviewers: Open in CodeFlow

* Initial plan

* Implement snapToInterval property for Fabric ScrollView

Co-authored-by: anupriya13 <[email protected]>

* Add safety checks to snapToInterval implementation and remove duplication

Co-authored-by: anupriya13 <[email protected]>

* Change files

* Run yarn change prerelease, lint:fix, and format as requested

Co-authored-by: anupriya13 <[email protected]>

* Remove changes in vnext/codegen files as requested

Co-authored-by: anupriya13 <[email protected]>

* Restore original inline snap points logic while preserving snapToInterval support

Co-authored-by: anupriya13 <[email protected]>

* Optimize snapToInterval performance by reducing recalculation frequency

Co-authored-by: anupriya13 <[email protected]>

* Revert commit 4bbc0b9 as requested

Co-authored-by: anupriya13 <[email protected]>

* Update ScrollViewComponentView.cpp

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: anupriya13 <[email protected]>
@anupriya13 anupriya13 marked this pull request as ready for review July 8, 2025 09:49
@anupriya13 anupriya13 requested a review from a team as a code owner July 8, 2025 09:49
@anupriya13 anupriya13 changed the title Implement snapToInterval property for ScrollView in Fabric [Fabric] Implement snapToInterval property for ScrollView Jul 9, 2025
@anupriya13
Copy link
Contributor Author

Waiting on review since long time > assigned to @sharath2727 for iteration 2507-02
Let's discuss any issues in PR here rather than offline so that it's documented

@@ -863,6 +878,9 @@ void ScrollViewComponentView::updateContentVisualSize() noexcept {
m_verticalScrollbarComponent->ContentSize(contentSize);
m_horizontalScrollbarComponent->ContentSize(contentSize);
m_scrollVisual.ContentSize(contentSize);

// Update snap points if snapToInterval is being used, as content size affects the number of snap points
updateSnapPoints();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the scenario for this? In the sense when would this be called? is it during initialization?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's whenever the content size is changed the offsets / intervals would be updated as per new dimensions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see. so basically if layout size changes during runtime and then this gets triggered. Got it. Thank you for helping me understand this code better. I hope all the tests are validated to the best of your knowledge.

Copy link
Contributor

@sharath2727 sharath2727 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with one pending question.

@anupriya13
Copy link
Contributor Author

Merging as discussed in the meeting

@anupriya13 anupriya13 merged commit 2cde3f1 into main Jul 15, 2025
58 checks passed
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.

Implement snapToInterval property for ScrollView for fabric
3 participants