diff --git a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs index 846728b101da..e30b92643c15 100644 --- a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs +++ b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.iOS.cs @@ -94,6 +94,7 @@ public static void MapItemsUpdatingScrollMode(ItemsViewHandler handl protected virtual void UpdateLayout() { _layout = SelectLayout(); + MapItemsUpdatingScrollMode(this, ItemsView); Controller?.UpdateLayout(_layout); } diff --git a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs index c9507bc884ba..164954275d28 100644 --- a/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs +++ b/src/Controls/src/Core/Handlers/Items2/CollectionViewHandler2.iOS.cs @@ -156,25 +156,26 @@ protected override UICollectionViewLayout SelectLayout() } var itemSizingStrategy = ItemsView.ItemSizingStrategy; + var itemsUpdatingScrollMode = ItemsView.ItemsUpdatingScrollMode; var itemsLayout = ItemsView.ItemsLayout; SubscribeToItemsLayoutPropertyChanged(itemsLayout); if (itemsLayout is GridItemsLayout gridItemsLayout) { - return LayoutFactory2.CreateGrid(gridItemsLayout, groupInfo, headerFooterInfo); + return LayoutFactory2.CreateGrid(gridItemsLayout, groupInfo, headerFooterInfo, itemsUpdatingScrollMode); } if (itemsLayout is LinearItemsLayout listItemsLayout) { - return LayoutFactory2.CreateList(listItemsLayout, groupInfo, headerFooterInfo); + return LayoutFactory2.CreateList(listItemsLayout, groupInfo, headerFooterInfo, itemsUpdatingScrollMode); } // Fall back to vertical list var fallbackItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Vertical); // Manually setting the value to ensure the property changed event is properly wired.. ItemsView.ItemsLayout = fallbackItemsLayout; - return LayoutFactory2.CreateList(fallbackItemsLayout, groupInfo, headerFooterInfo); + return LayoutFactory2.CreateList(fallbackItemsLayout, groupInfo, headerFooterInfo, itemsUpdatingScrollMode); } public static void MapHeaderTemplate(CollectionViewHandler2 handler, StructuredItemsView itemsView) diff --git a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs index 87cfb828150a..d3a385e86ffb 100644 --- a/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs +++ b/src/Controls/src/Core/Handlers/Items2/ItemsViewHandler2.iOS.cs @@ -117,7 +117,7 @@ public static void MapIsVisible(ItemsViewHandler2 handler, ItemsView public static void MapItemsUpdatingScrollMode(ItemsViewHandler2 handler, ItemsView itemsView) { - // TODO: Fix handler._layout.ItemsUpdatingScrollMode = itemsView.ItemsUpdatingScrollMode; + handler.UpdateLayout(); } //TODO: this is being called 2 times on startup, one from OnCreatePlatformView and otehr from the mapper for the layout diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs index 66bc21786d5d..8444bf1f1b74 100644 --- a/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs +++ b/src/Controls/src/Core/Handlers/Items2/iOS/LayoutFactory2.cs @@ -11,16 +11,16 @@ namespace Microsoft.Maui.Controls.Handlers.Items2; internal static class LayoutFactory2 { public static UICollectionViewLayout CreateList(LinearItemsLayout linearItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => linearItemsLayout.Orientation == ItemsLayoutOrientation.Vertical - ? CreateVerticalList(linearItemsLayout, groupingInfo, headerFooterInfo) - : CreateHorizontalList(linearItemsLayout, groupingInfo, headerFooterInfo); + ? CreateVerticalList(linearItemsLayout, groupingInfo, headerFooterInfo, itemsUpdatingScrollMode) + : CreateHorizontalList(linearItemsLayout, groupingInfo, headerFooterInfo, itemsUpdatingScrollMode); public static UICollectionViewLayout CreateGrid(GridItemsLayout gridItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => gridItemsLayout.Orientation == ItemsLayoutOrientation.Vertical - ? CreateVerticalGrid(gridItemsLayout, groupingInfo, headerFooterInfo) - : CreateHorizontalGrid(gridItemsLayout, groupingInfo, headerFooterInfo); + ? CreateVerticalGrid(gridItemsLayout, groupingInfo, headerFooterInfo, itemsUpdatingScrollMode) + : CreateHorizontalGrid(gridItemsLayout, groupingInfo, headerFooterInfo, itemsUpdatingScrollMode); static NSCollectionLayoutBoundarySupplementaryItem[] CreateSupplementaryItems(LayoutGroupingInfo? groupingInfo, LayoutHeaderFooterInfo? layoutHeaderFooterInfo, UICollectionViewScrollDirection scrollDirection, NSCollectionLayoutDimension width, NSCollectionLayoutDimension height) @@ -83,7 +83,7 @@ static NSCollectionLayoutBoundarySupplementaryItem[] CreateSupplementaryItems(La return []; } - static UICollectionViewLayout CreateListLayout(UICollectionViewScrollDirection scrollDirection, LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo layoutHeaderFooterInfo, LayoutSnapInfo snapInfo, NSCollectionLayoutDimension itemWidth, NSCollectionLayoutDimension itemHeight, NSCollectionLayoutDimension groupWidth, NSCollectionLayoutDimension groupHeight, double itemSpacing, Func? peekAreaInsetsFunc) + static UICollectionViewLayout CreateListLayout(UICollectionViewScrollDirection scrollDirection, LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo layoutHeaderFooterInfo, LayoutSnapInfo snapInfo, NSCollectionLayoutDimension itemWidth, NSCollectionLayoutDimension itemHeight, NSCollectionLayoutDimension groupWidth, NSCollectionLayoutDimension groupHeight, double itemSpacing, Func? peekAreaInsetsFunc, ItemsUpdatingScrollMode itemsUpdatingScrollMode) { var layoutConfiguration = new UICollectionViewCompositionalLayoutConfiguration(); layoutConfiguration.ScrollDirection = scrollDirection; @@ -137,14 +137,14 @@ static UICollectionViewLayout CreateListLayout(UICollectionViewScrollDirection s groupHeight); return section; - }, layoutConfiguration); + }, layoutConfiguration, itemsUpdatingScrollMode); return layout; } - static UICollectionViewLayout CreateGridLayout(UICollectionViewScrollDirection scrollDirection, LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, LayoutSnapInfo snapInfo, NSCollectionLayoutDimension itemWidth, NSCollectionLayoutDimension itemHeight, NSCollectionLayoutDimension groupWidth, NSCollectionLayoutDimension groupHeight, double verticalItemSpacing, double horizontalItemSpacing, int columns) + static UICollectionViewLayout CreateGridLayout(UICollectionViewScrollDirection scrollDirection, LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, LayoutSnapInfo snapInfo, NSCollectionLayoutDimension itemWidth, NSCollectionLayoutDimension itemHeight, NSCollectionLayoutDimension groupWidth, NSCollectionLayoutDimension groupHeight, double verticalItemSpacing, double horizontalItemSpacing, int columns, ItemsUpdatingScrollMode itemsUpdatingScrollMode) { var layoutConfiguration = new UICollectionViewCompositionalLayoutConfiguration(); layoutConfiguration.ScrollDirection = scrollDirection; @@ -189,13 +189,13 @@ static UICollectionViewLayout CreateGridLayout(UICollectionViewScrollDirection s groupHeight); return section; - }, layoutConfiguration); + }, layoutConfiguration, itemsUpdatingScrollMode); return layout; } public static UICollectionViewLayout CreateVerticalList(LinearItemsLayout linearItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => CreateListLayout(UICollectionViewScrollDirection.Vertical, groupingInfo, headerFooterInfo, @@ -207,11 +207,12 @@ public static UICollectionViewLayout CreateVerticalList(LinearItemsLayout linear NSCollectionLayoutDimension.CreateFractionalWidth(1f), NSCollectionLayoutDimension.CreateEstimated(30f), linearItemsLayout.ItemSpacing, - null); + null, + itemsUpdatingScrollMode); public static UICollectionViewLayout CreateHorizontalList(LinearItemsLayout linearItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => CreateListLayout(UICollectionViewScrollDirection.Horizontal, groupingInfo, headerFooterInfo, @@ -223,10 +224,11 @@ public static UICollectionViewLayout CreateHorizontalList(LinearItemsLayout line NSCollectionLayoutDimension.CreateEstimated(30f), NSCollectionLayoutDimension.CreateFractionalHeight(1f), linearItemsLayout.ItemSpacing, - null); + null, + itemsUpdatingScrollMode); public static UICollectionViewLayout CreateVerticalGrid(GridItemsLayout gridItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => CreateGridLayout(UICollectionViewScrollDirection.Vertical, groupingInfo, headerFooterInfo, @@ -241,11 +243,12 @@ public static UICollectionViewLayout CreateVerticalGrid(GridItemsLayout gridItem NSCollectionLayoutDimension.CreateEstimated(30f), gridItemsLayout.VerticalItemSpacing, gridItemsLayout.HorizontalItemSpacing, - gridItemsLayout.Span); + gridItemsLayout.Span, + itemsUpdatingScrollMode); public static UICollectionViewLayout CreateHorizontalGrid(GridItemsLayout gridItemsLayout, - LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo) + LayoutGroupingInfo groupingInfo, LayoutHeaderFooterInfo headerFooterInfo, ItemsUpdatingScrollMode itemsUpdatingScrollMode) => CreateGridLayout(UICollectionViewScrollDirection.Horizontal, groupingInfo, headerFooterInfo, @@ -260,7 +263,8 @@ public static UICollectionViewLayout CreateHorizontalGrid(GridItemsLayout gridIt NSCollectionLayoutDimension.CreateFractionalHeight(1f), gridItemsLayout.VerticalItemSpacing, gridItemsLayout.HorizontalItemSpacing, - gridItemsLayout.Span); + gridItemsLayout.Span, + itemsUpdatingScrollMode); #nullable disable @@ -396,9 +400,50 @@ public static UICollectionViewLayout CreateCarouselLayout( class CustomUICollectionViewCompositionalLayout : UICollectionViewCompositionalLayout { LayoutSnapInfo _snapInfo; - public CustomUICollectionViewCompositionalLayout(LayoutSnapInfo snapInfo, UICollectionViewCompositionalLayoutSectionProvider sectionProvider, UICollectionViewCompositionalLayoutConfiguration configuration) : base(sectionProvider, configuration) + ItemsUpdatingScrollMode _itemsUpdatingScrollMode; + + public CustomUICollectionViewCompositionalLayout(LayoutSnapInfo snapInfo, UICollectionViewCompositionalLayoutSectionProvider sectionProvider, UICollectionViewCompositionalLayoutConfiguration configuration, ItemsUpdatingScrollMode itemsUpdatingScrollMode) : base(sectionProvider, configuration) { _snapInfo = snapInfo; + _itemsUpdatingScrollMode = itemsUpdatingScrollMode; + } + + public override void FinalizeCollectionViewUpdates() + { + base.FinalizeCollectionViewUpdates(); + + if (_itemsUpdatingScrollMode == ItemsUpdatingScrollMode.KeepLastItemInView) + { + ForceScrollToLastItem(CollectionView); + } + } + + void ForceScrollToLastItem(UICollectionView collectionView) + { + var sections = (int)collectionView.NumberOfSections(); + + if (sections == 0) + { + return; + } + + for (int section = sections - 1; section >= 0; section--) + { + var itemCount = collectionView.NumberOfItemsInSection(section); + if (itemCount > 0) + { + var lastIndexPath = NSIndexPath.FromItemSection(itemCount - 1, section); + if (Configuration.ScrollDirection == UICollectionViewScrollDirection.Vertical) + { + collectionView.ScrollToItem(lastIndexPath, UICollectionViewScrollPosition.Bottom, true); + } + else + { + collectionView.ScrollToItem(lastIndexPath, UICollectionViewScrollPosition.Right, true); + } + return; + } + } } public override CGPoint TargetContentOffset(CGPoint proposedContentOffset, CGPoint scrollingVelocity) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28720.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue28720.xaml new file mode 100644 index 000000000000..c1e2b42e169b --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28720.xaml @@ -0,0 +1,49 @@ + + + +