Skip to content

Commit 4bbc0b9

Browse files
Copilotanupriya13
andcommitted
Optimize snapToInterval performance by reducing recalculation frequency
Co-authored-by: anupriya13 <[email protected]>
1 parent 0424e18 commit 4bbc0b9

File tree

2 files changed

+51
-21
lines changed

2 files changed

+51
-21
lines changed

vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -871,8 +871,13 @@ void ScrollViewComponentView::updateContentVisualSize() noexcept {
871871
m_horizontalScrollbarComponent->ContentSize(contentSize);
872872
m_scrollVisual.ContentSize(contentSize);
873873

874-
// Update snap points if snapToInterval is being used, as content size affects the number of snap points
875-
updateSnapPoints();
874+
// TODO: For optimal performance, snapToInterval should use InteractionTrackerInertiaRestingValue
875+
// with expression animations (similar to snapToEnd implementation) to avoid recalculating
876+
// all snap points on content size changes. For now, only update when actually needed.
877+
const auto &viewProps = *std::static_pointer_cast<const facebook::react::ScrollViewProps>(this->viewProps());
878+
if (viewProps.snapToInterval > 0 && viewProps.snapToOffsets.size() == 0) {
879+
updateSnapPointsForInterval();
880+
}
876881
}
877882

878883
void ScrollViewComponentView::prepareForRecycle() noexcept {}
@@ -1457,25 +1462,49 @@ void ScrollViewComponentView::updateSnapPoints() noexcept {
14571462
snapToOffsets.Append(static_cast<float>(offset));
14581463
}
14591464
} else if (viewProps.snapToInterval > 0) {
1460-
// Generate snap points based on interval
1461-
// Calculate the content size to determine how many intervals to create
1462-
float contentLength = viewProps.horizontal
1463-
? std::max(m_contentSize.width, m_layoutMetrics.frame.size.width) * m_layoutMetrics.pointScaleFactor
1464-
: std::max(m_contentSize.height, m_layoutMetrics.frame.size.height) * m_layoutMetrics.pointScaleFactor;
1465-
1466-
float interval = static_cast<float>(viewProps.snapToInterval) * m_layoutMetrics.pointScaleFactor;
1467-
1468-
// Ensure we have a reasonable minimum interval to avoid infinite loops or excessive memory usage
1469-
if (interval >= 1.0f && contentLength > 0) {
1470-
// Generate offsets at each interval, but limit the number of snap points to avoid excessive memory usage
1471-
const int maxSnapPoints = 1000; // Reasonable limit
1472-
int snapPointCount = 0;
1473-
1474-
for (float offset = 0; offset <= contentLength && snapPointCount < maxSnapPoints; offset += interval) {
1475-
snapToOffsets.Append(offset);
1476-
snapPointCount++;
1477-
}
1478-
}
1465+
// For snapToInterval, delegate to specialized method
1466+
updateSnapPointsForInterval();
1467+
return;
1468+
}
1469+
1470+
m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView());
1471+
}
1472+
1473+
void ScrollViewComponentView::updateSnapPointsForInterval() noexcept {
1474+
const auto &viewProps = *std::static_pointer_cast<const facebook::react::ScrollViewProps>(this->viewProps());
1475+
1476+
if (viewProps.snapToInterval <= 0) {
1477+
return;
1478+
}
1479+
1480+
const auto snapToOffsets = winrt::single_threaded_vector<float>();
1481+
float interval = static_cast<float>(viewProps.snapToInterval) * m_layoutMetrics.pointScaleFactor;
1482+
1483+
if (interval < 1.0f) {
1484+
return;
1485+
}
1486+
1487+
// Calculate the content size
1488+
float contentLength = viewProps.horizontal
1489+
? std::max(m_contentSize.width, m_layoutMetrics.frame.size.width) * m_layoutMetrics.pointScaleFactor
1490+
: std::max(m_contentSize.height, m_layoutMetrics.frame.size.height) * m_layoutMetrics.pointScaleFactor;
1491+
1492+
if (contentLength <= 0) {
1493+
return;
1494+
}
1495+
1496+
// Performance optimization: Instead of generating all possible snap points,
1497+
// generate a reasonable number based on the current viewport and content size.
1498+
// The composition system's InteractionTrackerInertiaRestingValue would be ideal
1499+
// for true dynamic calculation, but requires interface changes.
1500+
1501+
const int maxSnapPoints = 500; // Reduced from 1000 for better performance
1502+
int snapPointCount = 0;
1503+
1504+
// Generate snap points across the entire content length
1505+
for (float offset = 0; offset <= contentLength && snapPointCount < maxSnapPoints; offset += interval) {
1506+
snapToOffsets.Append(offset);
1507+
snapPointCount++;
14791508
}
14801509

14811510
m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView());

vnext/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
122122
void updateDecelerationRate(float value) noexcept;
123123
void updateContentVisualSize() noexcept;
124124
void updateSnapPoints() noexcept;
125+
void updateSnapPointsForInterval() noexcept;
125126
bool scrollToEnd(bool animate) noexcept;
126127
bool scrollToStart(bool animate) noexcept;
127128
bool scrollDown(float delta, bool animate) noexcept;

0 commit comments

Comments
 (0)