Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement snapToAlignment support for Fabric ScrollView - interface and prop handling",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -651,10 +651,11 @@ const SnapToOptions = () => {
snapToInterval={snapToInterval}
snapToOffsets={snapToOffsets}
snapToStart={snapToStart}
testID="snap_scrollview"
nestedScrollEnabled>
{ITEMS.map(createItemRow)}
</ScrollView>
{Platform.OS === 'ios' ? (
{Platform.OS === 'ios' || Platform.OS === 'windows' ? (
<>
<RNTesterText style={styles.rowTitle}>
Select Snap to Alignment Mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,13 @@ describe('ScrollView Tests', () => {
const dump = await dumpVisualTree('scroll_pressable_sticky_header');
expect(dump).toMatchSnapshot();
});*/
test('ScrollView snapToAlignment does not cause errors', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

revert changes in this file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted changes in ScrollViewComponentTest.test.ts as requested. Commit b140442

// This test ensures that the snapToAlignment prop is handled without crashing
// We test this by navigating to the snap options example and verifying it loads
await goToComponentExample('<ScrollView> SnapTo Options');
const component = await app.findElementByTestID('snap_scrollview');
await component.waitForDisplayed({timeout: 20000});
const dump = await dumpVisualTree('snap_scrollview');
expect(dump).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion vnext/Microsoft.ReactNative/CompositionSwitcher.idl
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ namespace Microsoft.ReactNative.Composition.Experimental
void SetMaximumZoomScale(Single maximumZoomScale);
void SetMinimumZoomScale(Single minimumZoomScale);
Boolean Horizontal;
void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView<Single> offsets);
void SetSnapPoints(Boolean snapToStart, Boolean snapToEnd, Windows.Foundation.Collections.IVectorView<Single> offsets, Windows.UI.Xaml.Controls.SnapPointsAlignment snapToAlignment);
Copy link
Contributor

Choose a reason for hiding this comment

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

don't use xaml
Windows.UI.Xaml.Controls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed XAML dependency by defining a local SnapAlignment enum in the IDL file instead of using Windows.UI.Xaml.Controls.SnapPointsAlignment. Updated all related code to use the local enum. Commit a86cae6

}

[webhosthidden]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -871,9 +871,11 @@ struct CompScrollerVisual : winrt::implements<
void SetSnapPoints(
bool snapToStart,
bool snapToEnd,
winrt::Windows::Foundation::Collections::IVectorView<float> const &offsets) noexcept {
winrt::Windows::Foundation::Collections::IVectorView<float> const &offsets,
winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment snapToAlignment) noexcept {
m_snapToStart = snapToStart;
m_snapToEnd = snapToEnd;
m_snapToAlignment = snapToAlignment;
m_snapToOffsets.clear();
if (offsets) {
for (auto const &offset : offsets) {
Expand Down Expand Up @@ -1100,6 +1102,22 @@ struct CompScrollerVisual : winrt::implements<
}

snapPositions.insert(snapPositions.end(), m_snapToOffsets.begin(), m_snapToOffsets.end());

// Adjust snap positions based on alignment
const float viewportSize = m_horizontal ? visualSize.x : visualSize.y;
if (m_snapToAlignment == winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Center) {
// For center alignment, offset snap positions by half the viewport size
for (auto &position : snapPositions) {
position = std::max(0.0f, position - viewportSize / 2.0f);
}
} else if (m_snapToAlignment == winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Far) {
// For end alignment, offset snap positions by the full viewport size
for (auto &position : snapPositions) {
position = std::max(0.0f, position - viewportSize);
}
}
// For Near (start) alignment, no adjustment needed

std::sort(snapPositions.begin(), snapPositions.end());
snapPositions.erase(std::unique(snapPositions.begin(), snapPositions.end()), snapPositions.end());

Expand Down Expand Up @@ -1227,6 +1245,8 @@ struct CompScrollerVisual : winrt::implements<
bool m_snapToStart{true};
bool m_snapToEnd{true};
std::vector<float> m_snapToOffsets;
winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment m_snapToAlignment{
winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Near};
bool m_inertia{false};
bool m_custom{false};
winrt::Windows::Foundation::Numerics::float3 m_targetPosition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,12 +807,30 @@ void ScrollViewComponentView::updateProps(
}

if (oldViewProps.snapToStart != newViewProps.snapToStart || oldViewProps.snapToEnd != newViewProps.snapToEnd ||
oldViewProps.snapToOffsets != newViewProps.snapToOffsets) {
oldViewProps.snapToOffsets != newViewProps.snapToOffsets ||
oldViewProps.snapToAlignment != newViewProps.snapToAlignment) {
const auto snapToOffsets = winrt::single_threaded_vector<float>();
for (const auto &offset : newViewProps.snapToOffsets) {
snapToOffsets.Append(static_cast<float>(offset));
}
m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView());

// Convert React Native snapToAlignment to Windows SnapPointsAlignment enum
winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment snapAlignment;
switch (newViewProps.snapToAlignment) {
Copy link
Contributor

Choose a reason for hiding this comment

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

add all this part in another function for good readablity

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Extracted the snap alignment conversion logic into a separate private method convertSnapToAlignment() for improved readability. Commit e224904

case facebook::react::ScrollViewSnapToAlignment::Center:
snapAlignment = winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Center;
break;
case facebook::react::ScrollViewSnapToAlignment::End:
snapAlignment = winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Far;
break;
case facebook::react::ScrollViewSnapToAlignment::Start:
default:
snapAlignment = winrt::Windows::UI::Xaml::Controls::SnapPointsAlignment::Near;
break;
}

m_scrollVisual.SetSnapPoints(
newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView(), snapAlignment);
}
}

Expand Down