File: Handlers\Items2\CollectionViewHandler2.iOS.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using System.Collections.Generic;
using System.Text;
using Foundation;
using Microsoft.Maui.Handlers;
using ObjCRuntime;
using UIKit;
 
namespace Microsoft.Maui.Controls.Handlers.Items2
{
	internal class LayoutHeaderFooterInfo
	{
		public IView FooterView { get; set; }
		public IView HeaderView { get; set; }
		public DataTemplate FooterTemplate { get; set; }
		public DataTemplate HeaderTemplate { get; set; }
		public bool HasHeader { get; set; }
		public bool HasFooter { get; set; }
	}
 
	internal class LayoutGroupingInfo
	{
		public bool IsGrouped { get; set; }
		public bool HasHeader { get; set; }
		public bool HasFooter { get; set; }
	}
 
	internal class LayoutSnapInfo
	{
		public SnapPointsAlignment SnapAligment { get; set; }
		public SnapPointsType SnapType { get; set; }
	}
 
	public partial class CollectionViewHandler2
	{
 
		public CollectionViewHandler2() : base(Mapper)
		{
 
 
		}
		public CollectionViewHandler2(PropertyMapper mapper = null) : base(mapper ?? Mapper)
		{
 
		}
 
		public static PropertyMapper<CollectionView, CollectionViewHandler2> Mapper = new(ItemsViewMapper)
		{
			[ReorderableItemsView.CanReorderItemsProperty.PropertyName] = MapCanReorderItems,
			[GroupableItemsView.IsGroupedProperty.PropertyName] = MapIsGrouped,
			[SelectableItemsView.SelectedItemProperty.PropertyName] = MapSelectedItem,
			[SelectableItemsView.SelectedItemsProperty.PropertyName] = MapSelectedItems,
			[SelectableItemsView.SelectionModeProperty.PropertyName] = MapSelectionMode,
			[StructuredItemsView.HeaderTemplateProperty.PropertyName] = MapHeaderTemplate,
			[StructuredItemsView.FooterTemplateProperty.PropertyName] = MapFooterTemplate,
			[StructuredItemsView.HeaderProperty.PropertyName] = MapHeaderTemplate,
			[StructuredItemsView.FooterProperty.PropertyName] = MapFooterTemplate,
		};
	}
 
	public partial class CollectionViewHandler2 : ItemsViewHandler2<ReorderableItemsView>
	{
		// Reorderable
		protected override ItemsViewController2<ReorderableItemsView> CreateController(ReorderableItemsView itemsView, UICollectionViewLayout layout)
			 => new ReorderableItemsViewController2<ReorderableItemsView>(itemsView, layout);
 
		public static void MapCanReorderItems(CollectionViewHandler2 handler, ReorderableItemsView itemsView)
		{
			(handler.Controller as ReorderableItemsViewController2<ReorderableItemsView>)?.UpdateCanReorderItems();
		}
 
		// Groupable
		protected override void ScrollToRequested(object sender, ScrollToRequestEventArgs args)
		{
			if (WillNeedScrollAdjustment(args))
			{
				if (args.IsAnimated)
				{
					(Controller as GroupableItemsViewController2<ReorderableItemsView>)?.SetScrollAnimationEndedCallback(() => base.ScrollToRequested(sender, args));
				}
				else
				{
					base.ScrollToRequested(sender, args);
				}
			}
 
			base.ScrollToRequested(sender, args);
		}
 
		public static void MapIsGrouped(CollectionViewHandler2 handler, GroupableItemsView itemsView)
		{
			handler.Controller?.UpdateItemsSource();
		}
 
		bool WillNeedScrollAdjustment(ScrollToRequestEventArgs args)
		{
			return ItemsView.ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems
				&& ItemsView.IsGrouped
				&& (args.ScrollToPosition == ScrollToPosition.End || args.ScrollToPosition == ScrollToPosition.MakeVisible);
		}
 
 
		// Selectable
		public static void MapItemsSource(CollectionViewHandler2 handler, SelectableItemsView itemsView)
		{
			ItemsViewHandler2<ReorderableItemsView>.MapItemsSource(handler, itemsView);
			MapSelectedItem(handler, itemsView);
		}
 
		public static void MapSelectedItem(CollectionViewHandler2 handler, SelectableItemsView itemsView)
		{
			(handler.Controller as SelectableItemsViewController2<ReorderableItemsView>)?.UpdatePlatformSelection();
		}
 
		public static void MapSelectedItems(CollectionViewHandler2 handler, SelectableItemsView itemsView)
		{
			(handler.Controller as SelectableItemsViewController2<ReorderableItemsView>)?.UpdatePlatformSelection();
		}
 
		public static void MapSelectionMode(CollectionViewHandler2 handler, SelectableItemsView itemsView)
		{
			(handler.Controller as SelectableItemsViewController2<ReorderableItemsView>)?.UpdateSelectionMode();
		}
 
 
		// Structured
		protected override UICollectionViewLayout SelectLayout()
		{
			var headerFooterInfo = new LayoutHeaderFooterInfo();
			var groupInfo = new LayoutGroupingInfo();
 
			if (ItemsView is GroupableItemsView groupableItemsView && groupableItemsView.IsGrouped)
			{
				groupInfo.IsGrouped = groupableItemsView.IsGrouped;
				groupInfo.HasHeader = groupableItemsView.GroupHeaderTemplate is not null;
				groupInfo.HasFooter = groupableItemsView.GroupFooterTemplate is not null;
			}
 
			if (ItemsView is StructuredItemsView structuredItemsView)
			{
				headerFooterInfo.HeaderTemplate = structuredItemsView.HeaderTemplate;
				headerFooterInfo.FooterTemplate = structuredItemsView.FooterTemplate;
				if (structuredItemsView.Header is View headerView)
				{
					headerFooterInfo.HeaderView = headerView;
				}
				if (structuredItemsView.Footer is View footerView)
				{
					headerFooterInfo.FooterView = footerView;
				}
				headerFooterInfo.HasHeader = structuredItemsView.Header is not null || structuredItemsView.HeaderTemplate is not null;
				headerFooterInfo.HasFooter = structuredItemsView.Footer is not null || structuredItemsView.FooterTemplate is not null;
			}
 
			var itemSizingStrategy = ItemsView.ItemSizingStrategy;
			var itemsLayout = ItemsView.ItemsLayout;
		
			SubscribeToItemsLayoutPropertyChanged(itemsLayout);
 
			if (itemsLayout is GridItemsLayout gridItemsLayout)
			{
				return LayoutFactory2.CreateGrid(gridItemsLayout, groupInfo, headerFooterInfo);
			}
 
			if (itemsLayout is LinearItemsLayout listItemsLayout)
			{
				return LayoutFactory2.CreateList(listItemsLayout, groupInfo, headerFooterInfo);
			}
 
			// 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);
		}
 
		public static void MapHeaderTemplate(CollectionViewHandler2 handler, StructuredItemsView itemsView)
		{
			handler.UpdateLayout();
			//	(handler.Controller as StructuredItemsViewController2<ReorderableItemsView>)?.UpdateHeaderView();
		}
 
		public static void MapFooterTemplate(CollectionViewHandler2 handler, StructuredItemsView itemsView)
		{
			handler.UpdateLayout();
			//(handler.Controller as StructuredItemsViewController2<ReorderableItemsView>)?.UpdateFooterView();
		}
 
		public static void MapItemsLayout(CollectionViewHandler2 handler, StructuredItemsView itemsView)
		{
			handler.UpdateLayout();
		}
 
		public static void MapItemSizingStrategy(CollectionViewHandler2 handler, StructuredItemsView itemsView)
		{
			handler.UpdateLayout();
		}
 
		void SubscribeToItemsLayoutPropertyChanged(IItemsLayout itemsLayout)
		{
			if(itemsLayout is not null)
			{
				itemsLayout.PropertyChanged += (sender, args) =>
				{
					if (args.PropertyName == nameof(ItemsLayout.SnapPointsAlignment) ||
						args.PropertyName == nameof(ItemsLayout.SnapPointsType) ||
						args.PropertyName == nameof(GridItemsLayout.VerticalItemSpacing) ||
						args.PropertyName == nameof(GridItemsLayout.HorizontalItemSpacing) ||
						args.PropertyName == nameof(GridItemsLayout.Span) ||
						args.PropertyName == nameof(LinearItemsLayout.ItemSpacing))
 
					{
						UpdateLayout();
					}
				};
			}
		}
	}
}