Skip to content
Open
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
@@ -0,0 +1,7 @@
namespace Microsoft.Maui.Controls.Handlers.Items;

// Implemented by delegators to allow explicit scroll-tracking reset when ItemsSource changes.
internal interface IScrollTrackingDelegator
{
void ResetScrollTracking();
}
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,15 @@ public virtual void UpdateItemsSource()
CollectionView.ReloadData();
CollectionView.CollectionViewLayout.InvalidateLayout();

// iOS/MacCatalyst: UIKit does not reset ContentOffset during ReloadData.
// ResetScrollTracking must run before the assignment so the UIKit-triggered
// scrollViewDidScroll callback computes delta from zero, not the stale previous offset.
if (CollectionView.ContentOffset != CoreGraphics.CGPoint.Empty)
{
(Delegator as IScrollTrackingDelegator)?.ResetScrollTracking();
CollectionView.ContentOffset = CoreGraphics.CGPoint.Empty;
}

(ItemsView as IView)?.InvalidateMeasure();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Microsoft.Maui.Controls.Handlers.Items
{
public class ItemsViewDelegator<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout
public class ItemsViewDelegator<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout, IScrollTrackingDelegator
where TItemsView : ItemsView
where TViewController : ItemsViewController<TItemsView>
{
Expand All @@ -25,6 +25,12 @@ public ItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController items
_viewController = new(itemsViewController);
}

void IScrollTrackingDelegator.ResetScrollTracking()
{
PreviousHorizontalOffset = 0;
PreviousVerticalOffset = 0;
}

public override void Scrolled(UIScrollView scrollView)
{
var (visibleItems, firstVisibleItemIndex, centerItemIndex, lastVisibleItemIndex) = GetVisibleItemsIndex();
Expand Down
10 changes: 10 additions & 0 deletions src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Controls.Handlers.Items;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Graphics;
using PassKit;
Expand Down Expand Up @@ -296,6 +297,15 @@ public virtual void UpdateItemsSource()
ReloadData();
CollectionView.CollectionViewLayout.InvalidateLayout();

// iOS/MacCatalyst: UIKit does not reset ContentOffset during ReloadData.
// ResetScrollTracking must run before the assignment so the UIKit-triggered
// scrollViewDidScroll callback computes delta from zero, not the stale previous offset.
if (CollectionView.ContentOffset != CoreGraphics.CGPoint.Empty)
{
(Delegator as IScrollTrackingDelegator)?.ResetScrollTracking();
CollectionView.ContentOffset = CoreGraphics.CGPoint.Empty;
}

(ItemsView as IView)?.InvalidateMeasure();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Microsoft.Maui.Controls.Handlers.Items2
{
public class ItemsViewDelegator2<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout
public class ItemsViewDelegator2<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout, IScrollTrackingDelegator
where TItemsView : ItemsView
where TViewController : ItemsViewController2<TItemsView>
{
Expand All @@ -26,6 +26,12 @@ public ItemsViewDelegator2(UICollectionViewLayout itemsViewLayout, TViewControll
_viewController = new(ItemsViewController2);
}

void IScrollTrackingDelegator.ResetScrollTracking()
{
PreviousHorizontalOffset = 0;
PreviousVerticalOffset = 0;
}

public override void Scrolled(UIScrollView scrollView)
{
var (visibleItems, firstVisibleItemIndex, centerItemIndex, lastVisibleItemIndex) = GetVisibleItemsIndex();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
</Grid.RowDefinitions>

<StackLayout Grid.Row="0" Orientation="Vertical" Spacing="5" BackgroundColor="Beige">
<Label LineBreakMode="WordWrap" Text="Scroll down into the list to increase vertical offset. Click NewItemsSource to reset items source. Verify that vertical offset becomes zero." HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
<Label x:Name="Label1" Text="VerticalOffset: 0" HorizontalTextAlignment="Center"/>
<Button Text="NewItemsSource" Clicked="NewItemsSourceClicked" HorizontalOptions="Center"/>
<Label LineBreakMode="WordWrap" Text="Tap ScrollToEnd to scroll the list, then tap NewItemsSource. Verify that vertical offset becomes zero." HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
<Label x:Name="Label1" AutomationId="VerticalOffsetLabel" Text="VerticalOffset: 0" HorizontalTextAlignment="Center"/>
<Button Text="ScrollToEnd" AutomationId="ScrollToEnd" Clicked="ScrollToEndClicked" HorizontalOptions="Center"/>
<Button Text="NewItemsSource" AutomationId="NewItemsSource" Clicked="NewItemsSourceClicked" HorizontalOptions="Center"/>
</StackLayout>

<CollectionView Grid.Row="1" AutomationId="CollectionView7993" ItemsSource="{Binding Items}" Scrolled="CollectionView_OnScrolled">
<CollectionView x:Name="CollectionView7993" Grid.Row="1" AutomationId="CollectionView7993" ItemsSource="{Binding Items}" Scrolled="CollectionView_OnScrolled">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="5"/>
</CollectionView.ItemsLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ void CollectionView_OnScrolled(object sender, ItemsViewScrolledEventArgs e)
Label1.Text = "VerticalOffset: " + e.VerticalOffset;
}

void ScrollToEndClicked(object sender, EventArgs e)
{
var vm = BindingContext as ViewModel7993;
if (vm?.Items.Count > 0)
{
CollectionView7993.ScrollTo(vm.Items[vm.Items.Count - 1]);
}
}

void NewItemsSourceClicked(object sender, EventArgs e)
{
BindingContext = new ViewModel7993();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_IOS //In MacCatalyst, the DragCoordinates is not supported. On the iOS platform, scroll position is not reset while update the itemsource. Issue: https://github.com/dotnet/maui/issues/26366
using NUnit.Framework;
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

Expand All @@ -17,16 +16,12 @@ public Issue7993(TestDevice testDevice) : base(testDevice)
[Category(UITestCategories.CollectionView)]
public void CollectionViewVerticalOffset()
{
var colView = App.WaitForElement("CollectionView7993");

App.WaitForElement("CollectionView7993");
App.WaitForElement("VerticalOffset: 0");
App.DragCoordinates(colView.GetRect().Width - 10,
colView.GetRect().Y + colView.GetRect().Height - 50,
colView.GetRect().Width - 10,
colView.GetRect().Y + 5);
App.Tap("ScrollToEnd");
App.WaitForElement("19");
App.WaitForNoElement("VerticalOffset: 0");
App.Tap("NewItemsSource");
App.WaitForElement("VerticalOffset: 0");
}
}
#endif
}
Loading