Skip to content

Commit f87e92f

Browse files
Copilotanupriya13
andauthored
Implement snapToAlignment property for ScrollView in Fabric architecture (#14830)
* Initial plan * Implement snapToAlignment support for Fabric ScrollView - interface and prop handling Co-authored-by: anupriya13 <[email protected]> * Add test support and UI for snapToAlignment in ScrollView Fabric implementation Co-authored-by: anupriya13 <[email protected]> * Remove unnecessary changes from vnext/codegen files Co-authored-by: anupriya13 <[email protected]> * Change files * Run yarn change prerelease, yarn lint:fix, and yarn format as requested Co-authored-by: anupriya13 <[email protected]> * Remove all changes from vnext/codegen files as requested Co-authored-by: anupriya13 <[email protected]> * Remove XAML dependency from IDL by defining local SnapAlignment enum Co-authored-by: anupriya13 <[email protected]> * Extract snap alignment conversion into separate function for better readability Co-authored-by: anupriya13 <[email protected]> * Revert changes to ScrollViewExample.js as requested Co-authored-by: anupriya13 <[email protected]> * Revert changes to ScrollViewComponentTest.test.ts as requested Co-authored-by: anupriya13 <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: anupriya13 <[email protected]>
1 parent 4a11d0d commit f87e92f

File tree

5 files changed

+58
-4
lines changed

5 files changed

+58
-4
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "Implement snapToAlignment support for Fabric ScrollView - interface and prop handling",
4+
"packageName": "react-native-windows",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

vnext/Microsoft.ReactNative/CompositionSwitcher.idl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ namespace Microsoft.ReactNative.Composition.Experimental
3131
SwitchThumb,
3232
};
3333

34+
enum SnapAlignment
35+
{
36+
Start,
37+
Center,
38+
End,
39+
};
40+
3441
[webhosthidden]
3542
[uuid("172def51-9e1a-4e3c-841a-e5a470065acc")] // uuid needed for empty interfaces
3643
[version(0)]
@@ -120,7 +127,7 @@ namespace Microsoft.ReactNative.Composition.Experimental
120127
void SetMaximumZoomScale(Single maximumZoomScale);
121128
void SetMinimumZoomScale(Single minimumZoomScale);
122129
Boolean Horizontal;
123-
void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView<Single> offsets);
130+
void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView<Single> offsets, SnapAlignment snapToAlignment);
124131
}
125132

126133
[webhosthidden]

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,9 +871,11 @@ struct CompScrollerVisual : winrt::implements<
871871
void SetSnapPoints(
872872
bool snapToStart,
873873
bool snapToEnd,
874-
winrt::Windows::Foundation::Collections::IVectorView<float> const &offsets) noexcept {
874+
winrt::Windows::Foundation::Collections::IVectorView<float> const &offsets,
875+
winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment snapToAlignment) noexcept {
875876
m_snapToStart = snapToStart;
876877
m_snapToEnd = snapToEnd;
878+
m_snapToAlignment = snapToAlignment;
877879
m_snapToOffsets.clear();
878880
if (offsets) {
879881
for (auto const &offset : offsets) {
@@ -1100,6 +1102,22 @@ struct CompScrollerVisual : winrt::implements<
11001102
}
11011103

11021104
snapPositions.insert(snapPositions.end(), m_snapToOffsets.begin(), m_snapToOffsets.end());
1105+
1106+
// Adjust snap positions based on alignment
1107+
const float viewportSize = m_horizontal ? visualSize.x : visualSize.y;
1108+
if (m_snapToAlignment == winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::Center) {
1109+
// For center alignment, offset snap positions by half the viewport size
1110+
for (auto &position : snapPositions) {
1111+
position = std::max(0.0f, position - viewportSize / 2.0f);
1112+
}
1113+
} else if (m_snapToAlignment == winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::End) {
1114+
// For end alignment, offset snap positions by the full viewport size
1115+
for (auto &position : snapPositions) {
1116+
position = std::max(0.0f, position - viewportSize);
1117+
}
1118+
}
1119+
// For Start alignment, no adjustment needed
1120+
11031121
std::sort(snapPositions.begin(), snapPositions.end());
11041122
snapPositions.erase(std::unique(snapPositions.begin(), snapPositions.end()), snapPositions.end());
11051123

@@ -1227,6 +1245,8 @@ struct CompScrollerVisual : winrt::implements<
12271245
bool m_snapToStart{true};
12281246
bool m_snapToEnd{true};
12291247
std::vector<float> m_snapToOffsets;
1248+
winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment m_snapToAlignment{
1249+
winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::Start};
12301250
bool m_inertia{false};
12311251
bool m_custom{false};
12321252
winrt::Windows::Foundation::Numerics::float3 m_targetPosition;

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,12 +807,17 @@ void ScrollViewComponentView::updateProps(
807807
}
808808

809809
if (oldViewProps.snapToStart != newViewProps.snapToStart || oldViewProps.snapToEnd != newViewProps.snapToEnd ||
810-
oldViewProps.snapToOffsets != newViewProps.snapToOffsets) {
810+
oldViewProps.snapToOffsets != newViewProps.snapToOffsets ||
811+
oldViewProps.snapToAlignment != newViewProps.snapToAlignment) {
811812
const auto snapToOffsets = winrt::single_threaded_vector<float>();
812813
for (const auto &offset : newViewProps.snapToOffsets) {
813814
snapToOffsets.Append(static_cast<float>(offset));
814815
}
815-
m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView());
816+
817+
auto snapAlignment = convertSnapToAlignment(newViewProps.snapToAlignment);
818+
819+
m_scrollVisual.SetSnapPoints(
820+
newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView(), snapAlignment);
816821
}
817822
}
818823

@@ -1435,4 +1440,17 @@ void ScrollViewComponentView::updateShowsVerticalScrollIndicator(bool value) noe
14351440
void ScrollViewComponentView::updateDecelerationRate(float value) noexcept {
14361441
m_scrollVisual.SetDecelerationRate({value, value, value});
14371442
}
1443+
1444+
winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment ScrollViewComponentView::convertSnapToAlignment(
1445+
facebook::react::ScrollViewSnapToAlignment alignment) noexcept {
1446+
switch (alignment) {
1447+
case facebook::react::ScrollViewSnapToAlignment::Center:
1448+
return winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::Center;
1449+
case facebook::react::ScrollViewSnapToAlignment::End:
1450+
return winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::End;
1451+
case facebook::react::ScrollViewSnapToAlignment::Start:
1452+
default:
1453+
return winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment::Start;
1454+
}
1455+
}
14381456
} // namespace winrt::Microsoft::ReactNative::Composition::implementation

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
134134
winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) noexcept;
135135
void updateShowsHorizontalScrollIndicator(bool value) noexcept;
136136
void updateShowsVerticalScrollIndicator(bool value) noexcept;
137+
winrt::Microsoft::ReactNative::Composition::Experimental::SnapAlignment convertSnapToAlignment(
138+
facebook::react::ScrollViewSnapToAlignment alignment) noexcept;
137139

138140
facebook::react::Size m_contentSize;
139141
winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual m_scrollVisual{nullptr};

0 commit comments

Comments
 (0)