Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -390,6 +390,13 @@ public virtual void ScrollTo(ScrollToRequestEventArgs args)

var position = DetermineTargetPosition(args);

// The collection view includes a header at the zeroth index, so the collection view scrolling is not correct using the index.
bool hasHeader = ItemsViewAdapter.ItemsSource.HasHeader;
if (hasHeader)
{
position += 1;
}
Comment on lines +393 to +398
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

This fix only addresses Android. The same issue likely exists on iOS, Windows, and MacCatalyst platforms. The iOS handler is in src/Controls/src/Core/Handlers/Items/iOS/ItemsViewHandler.iOS.cs and Windows handler in src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs. Both need similar fixes to account for headers when scrolling by index.

Check if the header offset needs to be applied in:

  • ItemsViewHandler.iOS.cs - ScrollToRequested method
  • ItemsViewHandler.Windows.cs - ScrollTo method

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The issue does not reproduce on Windows and iOS CV2.


if (args.IsAnimated)
{
ScrollHelper.AnimateScrollToPosition(position, args.ScrollToPosition);
Expand Down
56 changes: 56 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue27117.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue27117"
xmlns:cv2="clr-namespace:Maui.Controls.Sample"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues">

<ContentPage.BindingContext>
<local:_27117MainViewModel/>
</ContentPage.BindingContext>

<Grid RowDefinitions="Auto,*">
<Button Grid.Row="0"
Text="Scroll to First Item"
AutomationId="ScrollToFirstItemButton"
Clicked="ScrollToFirstItem_Clicked"/>

<cv2:CollectionView2 Grid.Row="1"
AutomationId="collectionView"
x:Name="collectionView"
x:DataType="local:_27117MainViewModel"
ItemsSource="{Binding _27117People}"
BackgroundColor="DarkGray">
<cv2:CollectionView2.Header>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="People"
AutomationId="HeaderLabel"
FontSize="Header"
FontAttributes="Bold"/>
</StackLayout>
</cv2:CollectionView2.Header>

<cv2:CollectionView2.ItemTemplate>
<DataTemplate x:DataType="local:_27117Person">
<VerticalStackLayout>
<Label Text="{Binding Name}"
AutomationId="{Binding Name}"
FontSize="Medium"/>
<Rectangle HeightRequest="2"
BackgroundColor="Black"/>
</VerticalStackLayout>
</DataTemplate>
</cv2:CollectionView2.ItemTemplate>

<cv2:CollectionView2.Footer>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Footer"
FontSize="Header"
FontAttributes="Bold"/>
</StackLayout>
</cv2:CollectionView2.Footer>
</cv2:CollectionView2>
</Grid>
</ContentPage>
43 changes: 43 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue27117.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 27117, "CollectionView ScrollTo not working under android", PlatformAffected.All)]
public partial class Issue27117 : ContentPage
{
public Issue27117()
{
InitializeComponent();
}

private void ScrollToFirstItem_Clicked(object sender, EventArgs e)
{
collectionView.ScrollTo(0, position: ScrollToPosition.Start, animate: false);
}
}

public class _27117MainViewModel : BindableObject
{
public ObservableCollection<_27117Person> _27117People { get; set; }
public _27117MainViewModel()
{
_27117People = new ObservableCollection<_27117Person>();
for (int i = 0; i < 100; i++)
{
_27117People.Add(new _27117Person($"Person {i}"));
}
}
}

public class _27117Person
{
public string Name { get; set; }

public _27117Person(string name)
{
Name = name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue27117 : _IssuesUITest
{
public Issue27117(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "CollectionView ScrollTo not working under android";

[Test]
[Category(UITestCategories.CollectionView)]
public void ScrollToIndexZeroShowsFirstItemNotHeader()
{
// Wait for CollectionView to load
App.WaitForElement("collectionView");

// Get Y position of header
var headerRect = App.WaitForElement("HeaderLabel").GetRect();
var headerY = headerRect.Y;

// Get initial Y position of "Person 0"
var initialRect = App.WaitForElement("Person 0").GetRect();
var initialY = initialRect.Y;

// Person 0 should be below the header initially
Assert.That(initialY, Is.GreaterThan(headerY),
"Person 0 should be below header initially");

// Tap button to scroll to index 0 with ScrollToPosition.Start
App.Tap("ScrollToFirstItemButton");
Task.Delay(1000).Wait();

// Get Y position after ScrollTo(0)
var afterScrollToRect = App.WaitForElement("Person 0").GetRect();
var afterScrollToY = afterScrollToRect.Y;

Assert.That(afterScrollToY, Is.LessThan(initialY),
$"ScrollTo(0) should scroll Person 0 to top, not push it down. " +
$"Initial Y={initialY}, After ScrollTo Y={afterScrollToY}. " +
$"If Y increased, the header was incorrectly treated as index 0.");
}
}
}
Loading