Generics for CollectionView iOS implementation (#7918)
authorE.Z. Hart <hartez@users.noreply.github.com>
Thu, 10 Oct 2019 23:21:22 +0000 (17:21 -0600)
committerSamantha Houts <samhouts@users.noreply.github.com>
Thu, 10 Oct 2019 23:21:22 +0000 (16:21 -0700)
* Make the ItemsView type generic

* Make controller type generic

* Generic all the things, and split up the delegators

Fix rebase error

17 files changed:
Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewController.cs
Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewDelegator.cs [new file with mode: 0644]
Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/CollectionViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/GroupableItemsViewController.cs
Xamarin.Forms.Platform.iOS/CollectionView/GroupableItemsViewDelegator.cs [new file with mode: 0644]
Xamarin.Forms.Platform.iOS/CollectionView/GroupableItemsViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewController.cs
Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewDelegator.cs [new file with mode: 0644]
Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/SelectableItemsViewController.cs
Xamarin.Forms.Platform.iOS/CollectionView/SelectableItemsViewDelegator.cs [new file with mode: 0644]
Xamarin.Forms.Platform.iOS/CollectionView/SelectableItemsViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/StructuredItemsViewController.cs
Xamarin.Forms.Platform.iOS/CollectionView/StructuredItemsViewRenderer.cs
Xamarin.Forms.Platform.iOS/CollectionView/UICollectionViewDelegator.cs [deleted file]
Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj

index ced46e8..936e02b 100644 (file)
@@ -7,21 +7,23 @@ using UIKit;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class CarouselViewController : ItemsViewController
+       public class CarouselViewController : ItemsViewController<CarouselView>
        {
                CarouselView _carouselView;
-               ItemsViewLayout _layout;
                bool _viewInitialized;
 
                public CarouselViewController(CarouselView itemsView, ItemsViewLayout layout) : base(itemsView, layout)
                {
                        _carouselView = itemsView;
-                       _layout = layout;
-                       Delegator.CarouselViewController = this;
                        CollectionView.AllowsSelection = false;
                        CollectionView.AllowsMultipleSelection = false;
                }
 
+               protected override UICollectionViewDelegateFlowLayout CreateDelegator()
+               {
+                       return new CarouselViewDelegator(ItemsViewLayout, this);
+               }
+
                public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
                {
                        var cell = base.GetCell(collectionView, indexPath);
diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewDelegator.cs b/Xamarin.Forms.Platform.iOS/CollectionView/CarouselViewDelegator.cs
new file mode 100644 (file)
index 0000000..26144b0
--- /dev/null
@@ -0,0 +1,28 @@
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS
+{
+       public class CarouselViewDelegator : ItemsViewDelegator<CarouselView, CarouselViewController>
+       {
+               public CarouselViewDelegator(ItemsViewLayout itemsViewLayout, CarouselViewController itemsViewController) 
+                       : base(itemsViewLayout, itemsViewController)
+               {
+               }
+
+               public override void DraggingStarted(UIScrollView scrollView)
+               {
+                       ViewController?.DraggingStarted(scrollView);
+
+                       PreviousHorizontalOffset = (float)scrollView.ContentOffset.X;
+                       PreviousVerticalOffset = (float)scrollView.ContentOffset.Y;
+               }
+
+               public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate)
+               {
+                       PreviousHorizontalOffset = 0;
+                       PreviousVerticalOffset = 0;
+
+                       ViewController?.DraggingEnded(scrollView, willDecelerate);
+               }
+       }
+}
\ No newline at end of file
index 1b1f355..236d4f2 100644 (file)
@@ -2,20 +2,18 @@
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class CarouselViewRenderer : ItemsViewRenderer
+       public class CarouselViewRenderer : ItemsViewRenderer<CarouselView, CarouselViewController>
        {
-               CarouselView CarouselView => (CarouselView)Element;
-
-               CarouselViewController CarouselViewController => (CarouselViewController)ItemsViewController;
+               CarouselView CarouselView => Element;
 
                public CarouselViewRenderer()
                {
                        CollectionView.VerifyCollectionViewFlagEnabled(nameof(CarouselViewRenderer));
                }
 
-               protected override ItemsViewController CreateController(ItemsView newElement, ItemsViewLayout layout)
+               protected override CarouselViewController CreateController(CarouselView newElement, ItemsViewLayout layout)
                {
-                       return new CarouselViewController(newElement as CarouselView, layout);
+                       return new CarouselViewController(newElement, layout);
                }
 
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
@@ -24,8 +22,8 @@ namespace Xamarin.Forms.Platform.iOS
 
                        if (changedProperty.IsOneOf(CarouselView.PeekAreaInsetsProperty, CarouselView.NumberOfSideItemsProperty))
                        {
-                               (CarouselViewController.Layout as CarouselViewLayout).UpdateConstraints(Frame.Size);
-                               CarouselViewController.Layout.InvalidateLayout();
+                               (Controller.Layout as CarouselViewLayout).UpdateConstraints(Frame.Size);
+                               Controller.Layout.InvalidateLayout();
                        }
                        else if (changedProperty.Is(CarouselView.IsSwipeEnabledProperty))
                                UpdateIsSwipeEnabled();
@@ -38,16 +36,16 @@ namespace Xamarin.Forms.Platform.iOS
                        return new CarouselViewLayout(CarouselView.ItemsLayout, CarouselView.ItemSizingStrategy, CarouselView);
                }
 
-               protected override void SetUpNewElement(ItemsView newElement)
+               protected override void SetUpNewElement(CarouselView newElement)
                {
                        base.SetUpNewElement(newElement);
                        UpdateIsSwipeEnabled();
                        UpdateIsBounceEnabled();
                }
 
-               protected override void TearDownOldElement(ItemsView oldElement)
+               protected override void TearDownOldElement(CarouselView oldElement)
                {
-                       CarouselViewController?.TearDown();
+                       Controller?.TearDown();
                        base.TearDownOldElement(oldElement);
                }
 
@@ -56,7 +54,7 @@ namespace Xamarin.Forms.Platform.iOS
                        if (CarouselView == null)
                                return;
 
-                       CarouselViewController.CollectionView.ScrollEnabled = CarouselView.IsSwipeEnabled;
+                       Controller.CollectionView.ScrollEnabled = CarouselView.IsSwipeEnabled;
                }
 
                void UpdateIsBounceEnabled()
@@ -64,7 +62,7 @@ namespace Xamarin.Forms.Platform.iOS
                        if (CarouselView == null)
                                return;
 
-                       CarouselViewController.CollectionView.Bounces = CarouselView.IsBounceEnabled;
+                       Controller.CollectionView.Bounces = CarouselView.IsBounceEnabled;
                }
        }
 }
index 23a6a66..6579a96 100644 (file)
@@ -1,4 +1,4 @@
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class CollectionViewRenderer : GroupableItemsViewRenderer { }
+       public class CollectionViewRenderer : GroupableItemsViewRenderer<GroupableItemsView, GroupableItemsViewController<GroupableItemsView>> { }
 }
\ No newline at end of file
index 5b8cae7..c134a2c 100644 (file)
@@ -5,28 +5,32 @@ using UIKit;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class GroupableItemsViewController : SelectableItemsViewController
+       public class GroupableItemsViewController<TItemsView> : SelectableItemsViewController<TItemsView>
+               where TItemsView : GroupableItemsView
        {
-               GroupableItemsView GroupableItemsView => (GroupableItemsView)ItemsView;
-
                // Keep a cached value for the current state of grouping around so we can avoid hitting the 
                // BindableProperty all the time 
                bool _isGrouped;
 
                Action _scrollAnimationEndedCallback;
 
-               public GroupableItemsViewController(GroupableItemsView groupableItemsView, ItemsViewLayout layout) 
+               public GroupableItemsViewController(TItemsView groupableItemsView, ItemsViewLayout layout) 
                        : base(groupableItemsView, layout)
                {
-                       _isGrouped = GroupableItemsView.IsGrouped;
+                       _isGrouped = ItemsView.IsGrouped;
+               }
+
+               protected override UICollectionViewDelegateFlowLayout CreateDelegator()
+               {
+                       return new GroupableItemsViewDelegator<TItemsView, GroupableItemsViewController<TItemsView>>(ItemsViewLayout, this);
                }
 
                protected override IItemsViewSource CreateItemsViewSource()
                {
                        // Use the BindableProperty here (instead of _isGroupingEnabled) because the cached value might not be set yet
-                       if (GroupableItemsView.IsGrouped) 
+                       if (ItemsView.IsGrouped) 
                        {
-                               return ItemsSourceFactory.CreateGrouped(GroupableItemsView.ItemsSource, CollectionView);
+                               return ItemsSourceFactory.CreateGrouped(ItemsView.ItemsSource, CollectionView);
                        }
 
                        return base.CreateItemsViewSource();
@@ -34,7 +38,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                public override void UpdateItemsSource()
                {
-                       _isGrouped = GroupableItemsView.IsGrouped;
+                       _isGrouped = ItemsView.IsGrouped;
                        base.UpdateItemsSource();
                }
 
@@ -91,8 +95,8 @@ namespace Xamarin.Forms.Platform.iOS
                void UpdateTemplatedSupplementaryView(TemplatedCell cell, NSString elementKind, NSIndexPath indexPath)
                {
                        DataTemplate template = elementKind == UICollectionElementKindSectionKey.Header
-                               ? GroupableItemsView.GroupHeaderTemplate
-                               : GroupableItemsView.GroupFooterTemplate;
+                               ? ItemsView.GroupHeaderTemplate
+                               : ItemsView.GroupFooterTemplate;
 
                        var bindingContext = ItemsSource.Group(indexPath);
 
@@ -108,10 +112,10 @@ namespace Xamarin.Forms.Platform.iOS
                {
                        if (elementKind == UICollectionElementKindSectionKey.Header)
                        {
-                               return DetermineViewReuseId(GroupableItemsView.GroupHeaderTemplate);
+                               return DetermineViewReuseId(ItemsView.GroupHeaderTemplate);
                        }
 
-                       return DetermineViewReuseId(GroupableItemsView.GroupFooterTemplate);
+                       return DetermineViewReuseId(ItemsView.GroupFooterTemplate);
                }
 
                string DetermineViewReuseId(DataTemplate template)
diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/GroupableItemsViewDelegator.cs b/Xamarin.Forms.Platform.iOS/CollectionView/GroupableItemsViewDelegator.cs
new file mode 100644 (file)
index 0000000..caa3ac5
--- /dev/null
@@ -0,0 +1,31 @@
+using System;
+using CoreGraphics;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS
+{
+       public class GroupableItemsViewDelegator<TItemsView, TViewController> : SelectableItemsViewDelegator<TItemsView, TViewController>
+               where TItemsView : GroupableItemsView
+               where TViewController : GroupableItemsViewController<TItemsView>
+       {
+               public GroupableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController) 
+                       : base(itemsViewLayout, itemsViewController)
+               {
+               }
+
+               public override CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
+               {
+                       return ViewController.GetReferenceSizeForHeader(collectionView, layout, section);
+               }
+
+               public override CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
+               {
+                       return ViewController.GetReferenceSizeForFooter(collectionView, layout, section);
+               }
+
+               public override void ScrollAnimationEnded(UIScrollView scrollView)
+               {
+                       ViewController?.HandleScrollAnimationEnded();
+               }
+       }
+}
\ No newline at end of file
index 99e711a..e08250c 100644 (file)
@@ -2,14 +2,13 @@
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class GroupableItemsViewRenderer : SelectableItemsViewRenderer
+       public class GroupableItemsViewRenderer<TItemsView, TViewController> : SelectableItemsViewRenderer<TItemsView, TViewController>
+               where TItemsView : GroupableItemsView
+               where TViewController : GroupableItemsViewController<TItemsView>
        {
-               GroupableItemsView GroupableItemsView => (GroupableItemsView)Element;
-               GroupableItemsViewController GroupableItemsViewController => (GroupableItemsViewController)ItemsViewController;
-
-               protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
+               protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
                {
-                       return new GroupableItemsViewController(itemsView as GroupableItemsView, layout);
+                       return new GroupableItemsViewController<TItemsView>(itemsView, layout) as TViewController;
                }
 
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
@@ -18,7 +17,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                        if (changedProperty.Is(GroupableItemsView.IsGroupedProperty))
                        {
-                               GroupableItemsViewController?.UpdateItemsSource();
+                               Controller?.UpdateItemsSource();
                        }
                }
 
@@ -45,7 +44,7 @@ namespace Xamarin.Forms.Platform.iOS
                        {
                                if (args.IsAnimated)
                                {
-                                       GroupableItemsViewController.SetScrollAnimationEndedCallback(() => base.ScrollToRequested(sender, args));
+                                       Controller.SetScrollAnimationEndedCallback(() => base.ScrollToRequested(sender, args));
                                }
                                else
                                {
@@ -58,8 +57,8 @@ namespace Xamarin.Forms.Platform.iOS
 
                bool WillNeedScrollAdjustment(ScrollToRequestEventArgs args)
                {
-                       return GroupableItemsView.ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems
-                               && GroupableItemsView.IsGrouped
+                       return ItemsView.ItemSizingStrategy == ItemSizingStrategy.MeasureAllItems
+                               && ItemsView.IsGrouped
                                && (args.ScrollToPosition == ScrollToPosition.End || args.ScrollToPosition == ScrollToPosition.MakeVisible);
                }
        }
index 2066359..8a2549b 100644 (file)
@@ -9,10 +9,11 @@ using Xamarin.Forms.Internals;
 namespace Xamarin.Forms.Platform.iOS
 {
        // TODO hartez 2018/06/01 14:21:24 Add a method for updating the layout 
-       public abstract class ItemsViewController : UICollectionViewController
+       public abstract class ItemsViewController<TItemsView> : UICollectionViewController
+               where TItemsView : ItemsView
        {
                public IItemsViewSource ItemsSource { get; protected set; }
-               public ItemsView ItemsView { get; }
+               public TItemsView ItemsView { get; }
                protected ItemsViewLayout ItemsViewLayout { get; set; }
                bool _initialConstraintsSet;
                bool _isEmpty;
@@ -23,9 +24,9 @@ namespace Xamarin.Forms.Platform.iOS
                UIView _emptyUIView;
                VisualElement _emptyViewFormsElement;
 
-               protected UICollectionViewDelegator Delegator { get; set; }
+               protected UICollectionViewDelegateFlowLayout Delegator { get; set; }
 
-               public ItemsViewController(ItemsView itemsView, ItemsViewLayout layout) : base(layout)
+               public ItemsViewController(TItemsView itemsView, ItemsViewLayout layout) : base(layout)
                {
                        ItemsView = itemsView;
                        ItemsSource = CreateItemsViewSource();
@@ -38,8 +39,6 @@ namespace Xamarin.Forms.Platform.iOS
                        ItemsViewLayout = layout;
                        ItemsViewLayout.GetPrototype = GetPrototype;
 
-                       // If we're updating from a previous layout, we should keep any settings for the SelectableItemsViewController around
-                       var selectableItemsViewController = Delegator?.SelectableItemsViewController;
                        Delegator = CreateDelegator();
 
                        CollectionView.Delegate = Delegator;
@@ -149,9 +148,9 @@ namespace Xamarin.Forms.Platform.iOS
                        }
                }
 
-               protected virtual UICollectionViewDelegator CreateDelegator()
+               protected virtual UICollectionViewDelegateFlowLayout CreateDelegator()
                {
-                       return new UICollectionViewDelegator(ItemsViewLayout, this);
+                       return new ItemsViewDelegator<TItemsView, ItemsViewController<TItemsView>>(ItemsViewLayout, this);
                }
 
                protected virtual IItemsViewSource CreateItemsViewSource()
diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewDelegator.cs b/Xamarin.Forms.Platform.iOS/CollectionView/ItemsViewDelegator.cs
new file mode 100644 (file)
index 0000000..b7dd96c
--- /dev/null
@@ -0,0 +1,125 @@
+using System;
+using System.Linq;
+using CoreGraphics;
+using Foundation;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS
+{
+       public class ItemsViewDelegator<TItemsView, TViewController> : UICollectionViewDelegateFlowLayout
+               where TItemsView : ItemsView
+               where TViewController : ItemsViewController<TItemsView>
+       {
+               public ItemsViewLayout ItemsViewLayout { get; }
+               public TViewController ViewController { get; }
+
+               protected float PreviousHorizontalOffset, PreviousVerticalOffset;
+
+               public ItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
+               {
+                       ItemsViewLayout = itemsViewLayout;
+                       ViewController = itemsViewController;
+               }
+
+               public override void Scrolled(UIScrollView scrollView)
+               {
+                       var indexPathsForVisibleItems = ViewController.CollectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
+
+                       if (indexPathsForVisibleItems.Count == 0)
+                               return;
+
+                       var contentInset = scrollView.ContentInset;
+                       var contentOffsetX = scrollView.ContentOffset.X + contentInset.Left;
+                       var contentOffsetY = scrollView.ContentOffset.Y + contentInset.Top;
+
+                       var firstVisibleItemIndex = (int)indexPathsForVisibleItems.First().Item;
+
+                       var collectionView = ViewController.CollectionView;
+                       var centerPoint = new CGPoint(collectionView.Center.X + collectionView.ContentOffset.X, collectionView.Center.Y + collectionView.ContentOffset.Y);
+                       var centerIndexPath = collectionView.IndexPathForItemAtPoint(centerPoint);
+                       var centerItemIndex = centerIndexPath?.Row ?? firstVisibleItemIndex;
+                       var lastVisibleItemIndex = (int)indexPathsForVisibleItems.Last().Item;
+                       var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
+                       {
+                               HorizontalDelta = contentOffsetX - PreviousHorizontalOffset,
+                               VerticalDelta = contentOffsetY - PreviousVerticalOffset,
+                               HorizontalOffset = contentOffsetX,
+                               VerticalOffset = contentOffsetY,
+                               FirstVisibleItemIndex = firstVisibleItemIndex,
+                               CenterItemIndex = centerItemIndex,
+                               LastVisibleItemIndex = lastVisibleItemIndex
+                       };
+
+                       var itemsView = ViewController.ItemsView;
+                       var source = ViewController.ItemsSource;
+                       itemsView.SendScrolled(itemsViewScrolledEventArgs);
+
+                       PreviousHorizontalOffset = (float)contentOffsetX;
+                       PreviousVerticalOffset = (float)contentOffsetY;
+
+                       switch (itemsView.RemainingItemsThreshold)
+                       {
+                               case -1:
+                                       return;
+                               case 0:
+                                       if (lastVisibleItemIndex == source.ItemCount - 1)
+                                               itemsView.SendRemainingItemsThresholdReached();
+                                       break;
+                               default:
+                                       if (source.ItemCount - 1 - lastVisibleItemIndex <= itemsView.RemainingItemsThreshold)
+                                               itemsView.SendRemainingItemsThresholdReached();
+                                       break;
+                       }
+               }
+
+               public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout,
+                       nint section)
+               {
+                       if (ItemsViewLayout == null)
+                       {
+                               return default;
+                       }
+
+                       return ItemsViewLayout.GetInsetForSection(collectionView, layout, section);
+               }
+
+               public override nfloat GetMinimumInteritemSpacingForSection(UICollectionView collectionView,
+                       UICollectionViewLayout layout, nint section)
+               {
+                       if (ItemsViewLayout == null)
+                       {
+                               return default;
+                       }
+
+                       return ItemsViewLayout.GetMinimumInteritemSpacingForSection(collectionView, layout, section);
+               }
+
+               public override nfloat GetMinimumLineSpacingForSection(UICollectionView collectionView,
+                       UICollectionViewLayout layout, nint section)
+               {
+                       if (ItemsViewLayout == null)
+                       {
+                               return default;
+                       }
+
+                       return ItemsViewLayout.GetMinimumLineSpacingForSection(collectionView, layout, section);
+               }
+
+               public override void CellDisplayingEnded(UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
+               {
+                       if (ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal)
+                       {
+                               var actualWidth = collectionView.ContentSize.Width - collectionView.Bounds.Size.Width;
+                               if (collectionView.ContentOffset.X >= actualWidth || collectionView.ContentOffset.X < 0)
+                                       return;
+                       }
+                       else
+                       {
+                               var actualHeight = collectionView.ContentSize.Height - collectionView.Bounds.Size.Height;
+
+                               if (collectionView.ContentOffset.Y >= actualHeight || collectionView.ContentOffset.Y < 0)
+                                       return;
+                       }
+               }
+       }
+}
\ No newline at end of file
index fddaabf..da58ed1 100644 (file)
@@ -4,28 +4,32 @@ using UIKit;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public abstract class ItemsViewRenderer : ViewRenderer<ItemsView, UIView>
+       public abstract class ItemsViewRenderer<TItemsView, TViewController> : ViewRenderer<TItemsView, UIView>
+               where TItemsView : ItemsView
+               where TViewController : ItemsViewController<TItemsView>
        {
                ItemsViewLayout _layout;
                bool _disposed;
                bool? _defaultHorizontalScrollVisibility;
                bool? _defaultVerticalScrollVisibility;
 
+               protected TItemsView ItemsView => Element;
+
                public ItemsViewRenderer()
                {
-                       CollectionView.VerifyCollectionViewFlagEnabled(nameof(ItemsViewRenderer));
+                       CollectionView.VerifyCollectionViewFlagEnabled(nameof(ItemsViewRenderer<TItemsView, TViewController>));
                }
 
-               public override UIViewController ViewController => ItemsViewController;
+               public override UIViewController ViewController => Controller;
 
-               protected ItemsViewController ItemsViewController { get; private set; }
+               protected TViewController Controller { get; private set; }
 
                public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
                {
                        return Control.GetSizeRequest(widthConstraint, heightConstraint, 0, 0);
                }
 
-               protected override void OnElementChanged(ElementChangedEventArgs<ItemsView> e)
+               protected override void OnElementChanged(ElementChangedEventArgs<TItemsView> e)
                {
                        TearDownOldElement(e.OldElement);
                        SetUpNewElement(e.NewElement);
@@ -37,31 +41,32 @@ namespace Xamarin.Forms.Platform.iOS
                {
                        base.OnElementPropertyChanged(sender, changedProperty);
 
-                       if (changedProperty.Is(ItemsView.ItemsSourceProperty))
+                       if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemsSourceProperty))
                        {
                                UpdateItemsSource();
                        }
-                       else if (changedProperty.Is(ItemsView.ItemTemplateProperty))
+                       else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemTemplateProperty))
                        {
                                UpdateLayout();
                        }
-                       else if (changedProperty.IsOneOf(ItemsView.EmptyViewProperty, ItemsView.EmptyViewTemplateProperty))
+                       else if (changedProperty.IsOneOf(Xamarin.Forms.ItemsView.EmptyViewProperty,
+                               Xamarin.Forms.ItemsView.EmptyViewTemplateProperty))
                        {
-                               ItemsViewController.UpdateEmptyView();
+                               Controller.UpdateEmptyView();
                        }
-                       else if (changedProperty.Is(ItemsView.ItemSizingStrategyProperty))
+                       else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemSizingStrategyProperty))
                        {
                                UpdateItemSizingStrategy();
                        }
-                       else if (changedProperty.Is(ItemsView.HorizontalScrollBarVisibilityProperty))
+                       else if (changedProperty.Is(Xamarin.Forms.ItemsView.HorizontalScrollBarVisibilityProperty))
                        {
                                UpdateHorizontalScrollBarVisibility();
                        }
-                       else if (changedProperty.Is(ItemsView.VerticalScrollBarVisibilityProperty))
+                       else if (changedProperty.Is(Xamarin.Forms.ItemsView.VerticalScrollBarVisibilityProperty))
                        {
                                UpdateVerticalScrollBarVisibility();
                        }
-                       else if (changedProperty.Is(ItemsView.ItemsUpdatingScrollModeProperty))
+                       else if (changedProperty.Is(Xamarin.Forms.ItemsView.ItemsUpdatingScrollModeProperty))
                        {
                                UpdateItemsUpdatingScrollMode();
                        }
@@ -69,7 +74,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                protected abstract ItemsViewLayout SelectLayout();
 
-               protected virtual void TearDownOldElement(ItemsView oldElement)
+               protected virtual void TearDownOldElement(TItemsView oldElement)
                {
                        if (oldElement == null)
                        {
@@ -80,7 +85,7 @@ namespace Xamarin.Forms.Platform.iOS
                        oldElement.ScrollToRequested -= ScrollToRequested;
                }
 
-               protected virtual void SetUpNewElement(ItemsView newElement)
+               protected virtual void SetUpNewElement(TItemsView newElement)
                {
                        if (newElement == null)
                        {
@@ -88,7 +93,7 @@ namespace Xamarin.Forms.Platform.iOS
                        }
 
                        UpdateLayout();
-                       ItemsViewController = CreateController(newElement, _layout);
+                       Controller = CreateController(newElement, _layout);
                         
                        if (Forms.IsiOS11OrNewer)
                        {
@@ -96,11 +101,11 @@ namespace Xamarin.Forms.Platform.iOS
                                // CollectionView content when we're in landscape mode (to avoid the notch)
                                // The SetUseSafeArea Platform Specific is already taking care of this for us 
                                // That said, at some point it's possible folks will want a PS for controlling this behavior
-                               ItemsViewController.CollectionView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
+                               Controller.CollectionView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
                        }
 
-                       SetNativeControl(ItemsViewController.View);
-                       ItemsViewController.CollectionView.BackgroundColor = UIColor.Clear;
+                       SetNativeControl(Controller.View);
+                       Controller.CollectionView.BackgroundColor = UIColor.Clear;
                        UpdateHorizontalScrollBarVisibility();
                        UpdateVerticalScrollBarVisibility();
 
@@ -112,9 +117,9 @@ namespace Xamarin.Forms.Platform.iOS
                {
                        _layout = SelectLayout();
 
-                       if (ItemsViewController != null)
+                       if (Controller != null)
                        {
-                               ItemsViewController.UpdateLayout(_layout);
+                               Controller.UpdateLayout(_layout);
                        }
                }
 
@@ -125,15 +130,15 @@ namespace Xamarin.Forms.Platform.iOS
 
                protected virtual void UpdateItemsUpdatingScrollMode()
                {
-                       _layout.ItemsUpdatingScrollMode = Element.ItemsUpdatingScrollMode;
+                       _layout.ItemsUpdatingScrollMode = ItemsView.ItemsUpdatingScrollMode;
                }
 
                protected virtual void UpdateItemsSource()
                {
-                       ItemsViewController.UpdateItemsSource();
+                       Controller.UpdateItemsSource();
                }
 
-               protected abstract ItemsViewController CreateController(ItemsView newElement, ItemsViewLayout layout);
+               protected abstract TViewController CreateController(TItemsView newElement, ItemsViewLayout layout);
 
                NSIndexPath DetermineIndex(ScrollToRequestEventArgs args)
                {
@@ -147,24 +152,24 @@ namespace Xamarin.Forms.Platform.iOS
                                return NSIndexPath.Create(args.GroupIndex, args.Index);
                        }
 
-                       return ItemsViewController.GetIndexForItem(args.Item);
+                       return Controller.GetIndexForItem(args.Item);
                }
 
                void UpdateVerticalScrollBarVisibility()
                {
                        if (_defaultVerticalScrollVisibility == null)
-                               _defaultVerticalScrollVisibility = ItemsViewController.CollectionView.ShowsVerticalScrollIndicator;
+                               _defaultVerticalScrollVisibility = Controller.CollectionView.ShowsVerticalScrollIndicator;
 
                        switch (Element.VerticalScrollBarVisibility)
                        {
                                case ScrollBarVisibility.Always:
-                                       ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = true;
+                                       Controller.CollectionView.ShowsVerticalScrollIndicator = true;
                                        break;
                                case ScrollBarVisibility.Never:
-                                       ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = false;
+                                       Controller.CollectionView.ShowsVerticalScrollIndicator = false;
                                        break;
                                case ScrollBarVisibility.Default:
-                                       ItemsViewController.CollectionView.ShowsVerticalScrollIndicator = _defaultVerticalScrollVisibility.Value;
+                                       Controller.CollectionView.ShowsVerticalScrollIndicator = _defaultVerticalScrollVisibility.Value;
                                        break;
                        }
                }
@@ -172,18 +177,18 @@ namespace Xamarin.Forms.Platform.iOS
                void UpdateHorizontalScrollBarVisibility()
                {
                        if (_defaultHorizontalScrollVisibility == null)
-                               _defaultHorizontalScrollVisibility = ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator;
+                               _defaultHorizontalScrollVisibility = Controller.CollectionView.ShowsHorizontalScrollIndicator;
 
                        switch (Element.HorizontalScrollBarVisibility)
                        {
                                case ScrollBarVisibility.Always:
-                                       ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = true;
+                                       Controller.CollectionView.ShowsHorizontalScrollIndicator = true;
                                        break;
                                case ScrollBarVisibility.Never:
-                                       ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = false;
+                                       Controller.CollectionView.ShowsHorizontalScrollIndicator = false;
                                        break;
                                case ScrollBarVisibility.Default:
-                                       ItemsViewController.CollectionView.ShowsHorizontalScrollIndicator = _defaultHorizontalScrollVisibility.Value;
+                                       Controller.CollectionView.ShowsHorizontalScrollIndicator = _defaultHorizontalScrollVisibility.Value;
                                        break;
                        }
                }
@@ -198,7 +203,7 @@ namespace Xamarin.Forms.Platform.iOS
                                        return;
                                }
 
-                               ItemsViewController.CollectionView.ScrollToItem(indexPath,
+                               Controller.CollectionView.ScrollToItem(indexPath,
                                        args.ScrollToPosition.ToCollectionViewScrollPosition(_layout.ScrollDirection), args.IsAnimated);
                        }
                }
@@ -216,8 +221,8 @@ namespace Xamarin.Forms.Platform.iOS
                        {
                                TearDownOldElement(Element);
 
-                               ItemsViewController?.Dispose();
-                               ItemsViewController = null;
+                               Controller?.Dispose();
+                               Controller = null;
                        }
 
                        base.Dispose(disposing);
@@ -230,7 +235,7 @@ namespace Xamarin.Forms.Platform.iOS
                                return false;
                        }
 
-                       var collectionView = ItemsViewController.CollectionView;
+                       var collectionView = Controller.CollectionView;
                        if (indexPath.Section >= collectionView.NumberOfSections())
                        {
                                return false;
index 1f8f4fc..9870c82 100644 (file)
@@ -5,15 +5,19 @@ using UIKit;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class SelectableItemsViewController : StructuredItemsViewController
+       public class SelectableItemsViewController<TItemsView> : StructuredItemsViewController<TItemsView>
+               where TItemsView : SelectableItemsView
        {
-               SelectableItemsView SelectableItemsView => (SelectableItemsView)ItemsView;
-
-               public SelectableItemsViewController(SelectableItemsView selectableItemsView, ItemsViewLayout layout) 
+               public SelectableItemsViewController(TItemsView selectableItemsView, ItemsViewLayout layout) 
                        : base(selectableItemsView, layout)
                {
                }
 
+               protected override UICollectionViewDelegateFlowLayout CreateDelegator()
+               {
+                       return new SelectableItemsViewDelegator<TItemsView, SelectableItemsViewController<TItemsView>>(ItemsViewLayout, this);
+               }
+
                // _Only_ called if the user initiates the selection change; will not be called for programmatic selection
                public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
                {
@@ -50,24 +54,24 @@ namespace Xamarin.Forms.Platform.iOS
 
                void FormsSelectItem(NSIndexPath indexPath)
                {
-                       var mode = SelectableItemsView.SelectionMode;
+                       var mode = ItemsView.SelectionMode;
 
                        switch (mode)
                        {
                                case SelectionMode.None:
                                        break;
                                case SelectionMode.Single:
-                                       SelectableItemsView.SelectedItem = GetItemAtIndex(indexPath);
+                                       ItemsView.SelectedItem = GetItemAtIndex(indexPath);
                                        break;
                                case SelectionMode.Multiple:
-                                       SelectableItemsView.SelectedItems.Add(GetItemAtIndex(indexPath));
+                                       ItemsView.SelectedItems.Add(GetItemAtIndex(indexPath));
                                        break;
                        }
                }
 
                void FormsDeselectItem(NSIndexPath indexPath)
                {
-                       var mode = SelectableItemsView.SelectionMode;
+                       var mode = ItemsView.SelectionMode;
 
                        switch (mode)
                        {
@@ -76,26 +80,26 @@ namespace Xamarin.Forms.Platform.iOS
                                case SelectionMode.Single:
                                        break;
                                case SelectionMode.Multiple:
-                                       SelectableItemsView.SelectedItems.Remove(GetItemAtIndex(indexPath));
+                                       ItemsView.SelectedItems.Remove(GetItemAtIndex(indexPath));
                                        break;
                        }
                }
 
                internal void UpdateNativeSelection()
                {
-                       if (SelectableItemsView == null)
+                       if (ItemsView == null)
                        {
                                return;
                        }
 
-                       var mode = SelectableItemsView.SelectionMode;
+                       var mode = ItemsView.SelectionMode;
 
                        switch (mode)
                        {
                                case SelectionMode.None:
                                        return;
                                case SelectionMode.Single:
-                                       var selectedItem = SelectableItemsView.SelectedItem;
+                                       var selectedItem = ItemsView.SelectedItem;
 
                                        if (selectedItem != null)
                                        {
@@ -116,7 +120,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                internal void UpdateSelectionMode()
                {
-                       var mode = SelectableItemsView.SelectionMode;
+                       var mode = ItemsView.SelectionMode;
 
                        switch (mode)
                        {
@@ -139,7 +143,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                void SynchronizeNativeSelectionWithSelectedItems()
                {
-                       var selectedItems = SelectableItemsView.SelectedItems;
+                       var selectedItems = ItemsView.SelectedItems;
                        var selectedIndexPaths = CollectionView.GetIndexPathsForSelectedItems();
 
                        foreach (var path in selectedIndexPaths)
diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/SelectableItemsViewDelegator.cs b/Xamarin.Forms.Platform.iOS/CollectionView/SelectableItemsViewDelegator.cs
new file mode 100644 (file)
index 0000000..c1b17e3
--- /dev/null
@@ -0,0 +1,25 @@
+using Foundation;
+using UIKit;
+
+namespace Xamarin.Forms.Platform.iOS
+{
+       public class SelectableItemsViewDelegator<TItemsView, TViewController> : ItemsViewDelegator<TItemsView, TViewController>
+               where TItemsView : SelectableItemsView
+               where TViewController : SelectableItemsViewController<TItemsView>
+       {
+               public SelectableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController) 
+                       : base(itemsViewLayout, itemsViewController)
+               {
+               }
+
+               public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
+               {
+                       ViewController?.ItemSelected(collectionView, indexPath);
+               }
+
+               public override void ItemDeselected(UICollectionView collectionView, NSIndexPath indexPath)
+               {
+                       ViewController?.ItemDeselected(collectionView, indexPath);
+               }
+       }
+}
\ No newline at end of file
index 45d6380..115d7d1 100644 (file)
@@ -3,14 +3,13 @@ using System.ComponentModel;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class SelectableItemsViewRenderer : StructuredItemsViewRenderer
+       public class SelectableItemsViewRenderer<TItemsView, TViewController> : StructuredItemsViewRenderer<TItemsView, TViewController>
+               where TItemsView : SelectableItemsView
+               where TViewController : SelectableItemsViewController<TItemsView>
        {
-               SelectableItemsView SelectableItemsView => (SelectableItemsView)Element;
-               SelectableItemsViewController SelectableItemsViewController => (SelectableItemsViewController)ItemsViewController;
-
-               protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
+               protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
                {
-                       return new SelectableItemsViewController(itemsView as SelectableItemsView, layout);
+                       return new SelectableItemsViewController<TItemsView>(itemsView, layout) as TViewController;
                }
 
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
@@ -27,13 +26,8 @@ namespace Xamarin.Forms.Platform.iOS
                        }
                }
 
-               protected override void SetUpNewElement(ItemsView newElement)
+               protected override void SetUpNewElement(TItemsView newElement)
                {
-                       if (newElement != null && !(newElement is SelectableItemsView))
-                       {
-                               throw new ArgumentException($"{nameof(newElement)} must be of type {typeof(SelectableItemsView).Name}");
-                       }
-
                        base.SetUpNewElement(newElement);
 
                        if (newElement == null)
@@ -47,12 +41,12 @@ namespace Xamarin.Forms.Platform.iOS
 
                protected virtual void UpdateNativeSelection()
                {
-                       SelectableItemsViewController.UpdateNativeSelection();
+                       Controller.UpdateNativeSelection();
                }
 
                protected virtual void UpdateSelectionMode()
                {
-                       SelectableItemsViewController.UpdateSelectionMode();
+                       Controller.UpdateSelectionMode();
                }
 
                protected override void UpdateItemsSource()
index 5adcb38..c5bef8b 100644 (file)
@@ -3,19 +3,18 @@ using UIKit;
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class StructuredItemsViewController : ItemsViewController
+       public class StructuredItemsViewController<TItemsView> : ItemsViewController<TItemsView>
+               where TItemsView : StructuredItemsView
        {
                bool _disposed;
 
-               StructuredItemsView StructuredItemsView => (StructuredItemsView)ItemsView;
-
                UIView _headerUIView;
                VisualElement _headerViewFormsElement;
 
                UIView _footerUIView;
                VisualElement _footerViewFormsElement;
 
-               public StructuredItemsViewController(StructuredItemsView structuredItemsView, ItemsViewLayout layout)
+               public StructuredItemsViewController(TItemsView structuredItemsView, ItemsViewLayout layout)
                        : base(structuredItemsView, layout)
                {
                }
@@ -41,7 +40,7 @@ namespace Xamarin.Forms.Platform.iOS
                        base.Dispose(disposing);
                }
 
-               protected override bool IsHorizontal => (StructuredItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
+               protected override bool IsHorizontal => (ItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
 
                public override void ViewWillLayoutSubviews()
                {
@@ -66,14 +65,14 @@ namespace Xamarin.Forms.Platform.iOS
 
                internal void UpdateFooterView()
                {
-                       UpdateSubview(StructuredItemsView?.Footer, StructuredItemsView?.FooterTemplate, 
+                       UpdateSubview(ItemsView?.Footer, ItemsView?.FooterTemplate, 
                                ref _footerUIView, ref _footerViewFormsElement);
                        UpdateHeaderFooterPosition();
                }
 
                internal void UpdateHeaderView()
                {
-                       UpdateSubview(StructuredItemsView?.Header, StructuredItemsView?.HeaderTemplate, 
+                       UpdateSubview(ItemsView?.Header, ItemsView?.HeaderTemplate, 
                                ref _headerUIView, ref _headerViewFormsElement);
                        UpdateHeaderFooterPosition();
                }
index 7233786..8dcb855 100644 (file)
@@ -2,14 +2,13 @@
 
 namespace Xamarin.Forms.Platform.iOS
 {
-       public class StructuredItemsViewRenderer : ItemsViewRenderer
+       public class StructuredItemsViewRenderer<TItemsView, TViewController> : ItemsViewRenderer<TItemsView, TViewController>
+               where TItemsView : StructuredItemsView
+               where TViewController : StructuredItemsViewController<TItemsView>
        {
-               StructuredItemsView StructuredItemsView => (StructuredItemsView)Element;
-               StructuredItemsViewController StructuredItemsViewController => (StructuredItemsViewController)ItemsViewController;
-
-               protected override ItemsViewController CreateController(ItemsView itemsView, ItemsViewLayout layout)
+               protected override TViewController CreateController(TItemsView itemsView, ItemsViewLayout layout)
                {
-                       return new StructuredItemsViewController(itemsView as StructuredItemsView, layout);
+                       return new StructuredItemsViewController<TItemsView>(itemsView, layout) as TViewController;
                }
 
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
@@ -18,19 +17,19 @@ namespace Xamarin.Forms.Platform.iOS
 
                        if (changedProperty.IsOneOf(StructuredItemsView.HeaderProperty, StructuredItemsView.HeaderTemplateProperty))
                        {
-                               StructuredItemsViewController.UpdateHeaderView();
+                               UpdateHeaderView();
                        }
                        else if (changedProperty.IsOneOf(StructuredItemsView.FooterProperty, StructuredItemsView.FooterTemplateProperty))
                        {
-                               StructuredItemsViewController.UpdateFooterView();
+                               UpdateFooterView();
                        }
                        else if (changedProperty.Is(StructuredItemsView.ItemsLayoutProperty))
                        {
-                               StructuredItemsViewController.UpdateLayout(SelectLayout());
+                               UpdateLayout();
                        }
                }
 
-               protected override void SetUpNewElement(ItemsView newElement)
+               protected override void SetUpNewElement(TItemsView newElement)
                {
                        base.SetUpNewElement(newElement);
 
@@ -39,14 +38,14 @@ namespace Xamarin.Forms.Platform.iOS
                                return;
                        }
 
-                       StructuredItemsViewController.UpdateFooterView();
-                       StructuredItemsViewController.UpdateHeaderView();
+                       Controller.UpdateFooterView();
+                       Controller.UpdateHeaderView();
                }
 
                protected override ItemsViewLayout SelectLayout()
                {
-                       var itemSizingStrategy = StructuredItemsView.ItemSizingStrategy;
-                       var itemsLayout = StructuredItemsView.ItemsLayout;
+                       var itemSizingStrategy = ItemsView.ItemSizingStrategy;
+                       var itemsLayout = ItemsView.ItemsLayout;
 
                        if (itemsLayout is GridItemsLayout gridItemsLayout)
                        {
@@ -62,10 +61,20 @@ namespace Xamarin.Forms.Platform.iOS
                        return new ListViewLayout(new LinearItemsLayout(ItemsLayoutOrientation.Vertical), itemSizingStrategy);
                }
 
+               protected virtual void UpdateHeaderView()
+               {
+                       Controller.UpdateHeaderView();
+               }
+
+               protected virtual void UpdateFooterView()
+               {
+                       Controller.UpdateFooterView();
+               }
+
                public override void LayoutSubviews()
                {
                        base.LayoutSubviews();
-                       StructuredItemsViewController.UpdateLayoutMeasurements();
+                       Controller.UpdateLayoutMeasurements();
                }
        }
 }
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.iOS/CollectionView/UICollectionViewDelegator.cs b/Xamarin.Forms.Platform.iOS/CollectionView/UICollectionViewDelegator.cs
deleted file mode 100644 (file)
index b752f76..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-using System;
-using System.Linq;
-using CoreGraphics;
-using Foundation;
-using UIKit;
-
-namespace Xamarin.Forms.Platform.iOS
-{
-       public class UICollectionViewDelegator : UICollectionViewDelegateFlowLayout
-       {
-               float _previousHorizontalOffset, _previousVerticalOffset;
-
-               public ItemsViewLayout ItemsViewLayout { get; }
-               public ItemsViewController ItemsViewController { get; }
-               public SelectableItemsViewController SelectableItemsViewController => ItemsViewController as SelectableItemsViewController;
-
-               public GroupableItemsViewController GroupableItemsViewController => ItemsViewController as GroupableItemsViewController;
-
-               public UICollectionViewDelegator(ItemsViewLayout itemsViewLayout, ItemsViewController itemsViewController)
-               {
-                       ItemsViewLayout = itemsViewLayout;
-                       ItemsViewController = itemsViewController;
-               }
-               public CarouselViewController CarouselViewController { get; set; }
-
-               public override void DraggingStarted(UIScrollView scrollView)
-               {
-                       CarouselViewController?.DraggingStarted(scrollView);
-
-                       _previousHorizontalOffset = (float)scrollView.ContentOffset.X;
-                       _previousVerticalOffset = (float)scrollView.ContentOffset.Y;
-               }
-
-               public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate)
-               {
-                       _previousHorizontalOffset = 0;
-                       _previousVerticalOffset = 0;
-
-                       CarouselViewController?.DraggingEnded(scrollView, willDecelerate);
-               }
-
-               public override void Scrolled(UIScrollView scrollView)
-               {
-                       var indexPathsForVisibleItems = ItemsViewController.CollectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
-
-                       if (indexPathsForVisibleItems.Count == 0)
-                               return;
-
-                       var contentInset = scrollView.ContentInset;
-                       var contentOffsetX = scrollView.ContentOffset.X + contentInset.Left;
-                       var contentOffsetY = scrollView.ContentOffset.Y + contentInset.Top;
-
-                       var firstVisibleItemIndex = (int)indexPathsForVisibleItems.First().Item;
-                       var centerPoint = new CGPoint(ItemsViewController.CollectionView.Center.X + ItemsViewController.CollectionView.ContentOffset.X, ItemsViewController.CollectionView.Center.Y + ItemsViewController.CollectionView.ContentOffset.Y);
-                       var centerIndexPath = ItemsViewController.CollectionView.IndexPathForItemAtPoint(centerPoint);
-                       var centerItemIndex = centerIndexPath?.Row ?? firstVisibleItemIndex;
-                       var lastVisibleItemIndex = (int)indexPathsForVisibleItems.Last().Item;
-                       var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
-                       {
-                               HorizontalDelta = contentOffsetX - _previousHorizontalOffset,
-                               VerticalDelta = contentOffsetY - _previousVerticalOffset,
-                               HorizontalOffset = contentOffsetX,
-                               VerticalOffset = contentOffsetY,
-                               FirstVisibleItemIndex = firstVisibleItemIndex,
-                               CenterItemIndex = centerItemIndex,
-                               LastVisibleItemIndex = lastVisibleItemIndex
-                       };
-
-                       ItemsViewController.ItemsView.SendScrolled(itemsViewScrolledEventArgs);
-
-                       _previousHorizontalOffset = (float)contentOffsetX;
-                       _previousVerticalOffset = (float)contentOffsetY;
-
-                       switch (ItemsViewController.ItemsView.RemainingItemsThreshold)
-                       {
-                               case -1:
-                                       return;
-                               case 0:
-                                       if (lastVisibleItemIndex == ItemsViewController.ItemsSource.ItemCount - 1)
-                                               ItemsViewController.ItemsView.SendRemainingItemsThresholdReached();
-                                       break;
-                               default:
-                                       if (ItemsViewController.ItemsSource.ItemCount - 1 - lastVisibleItemIndex <= ItemsViewController.ItemsView.RemainingItemsThreshold)
-                                               ItemsViewController.ItemsView.SendRemainingItemsThresholdReached();
-                                       break;
-                       }
-               }
-
-               public override UIEdgeInsets GetInsetForSection(UICollectionView collectionView, UICollectionViewLayout layout,
-                       nint section)
-               {
-                       if (ItemsViewLayout == null)
-                       {
-                               return default(UIEdgeInsets);
-                       }
-
-                       return ItemsViewLayout.GetInsetForSection(collectionView, layout, section);
-               }
-
-               public override nfloat GetMinimumInteritemSpacingForSection(UICollectionView collectionView,
-                       UICollectionViewLayout layout, nint section)
-               {
-                       if (ItemsViewLayout == null)
-                       {
-                               return default(nfloat);
-                       }
-
-                       return ItemsViewLayout.GetMinimumInteritemSpacingForSection(collectionView, layout, section);
-               }
-
-               public override nfloat GetMinimumLineSpacingForSection(UICollectionView collectionView,
-                       UICollectionViewLayout layout, nint section)
-               {
-                       if (ItemsViewLayout == null)
-                       {
-                               return default(nfloat);
-                       }
-
-                       return ItemsViewLayout.GetMinimumLineSpacingForSection(collectionView, layout, section);
-               }
-
-               public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
-               {
-                       SelectableItemsViewController?.ItemSelected(collectionView, indexPath);
-               }
-
-               public override void ItemDeselected(UICollectionView collectionView, NSIndexPath indexPath)
-               {
-                       SelectableItemsViewController?.ItemDeselected(collectionView, indexPath);
-               }
-
-               public override void CellDisplayingEnded(UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
-               {
-                       if (ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal)
-                       {
-                               var actualWidth = collectionView.ContentSize.Width - collectionView.Bounds.Size.Width;
-                               if (collectionView.ContentOffset.X >= actualWidth || collectionView.ContentOffset.X < 0)
-                                       return;
-                       }
-                       else
-                       {
-                               var actualHeight = collectionView.ContentSize.Height - collectionView.Bounds.Size.Height;
-
-                               if (collectionView.ContentOffset.Y >= actualHeight || collectionView.ContentOffset.Y < 0)
-                                       return;
-                       }
-               }
-
-               public override CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
-               {
-                       if (GroupableItemsViewController == null)
-                       {
-                               return CGSize.Empty;
-                       }
-
-                       return GroupableItemsViewController.GetReferenceSizeForHeader(collectionView, layout, section);
-               }
-
-               public override CGSize GetReferenceSizeForFooter(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
-               {
-                       if (GroupableItemsViewController == null)
-                       {
-                               return CGSize.Empty;
-                       }
-
-                       return GroupableItemsViewController.GetReferenceSizeForFooter(collectionView, layout, section);
-               }
-
-               public override void ScrollAnimationEnded(UIScrollView scrollView)
-               {
-                       GroupableItemsViewController?.HandleScrollAnimationEnded();
-               }
-       }
-}
\ No newline at end of file
index 65be26b..0c633b9 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Properties\AssemblyInfo.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Extensions\CellExtensions.cs" />
     <Compile Include="CADisplayLinkTicker.cs" />
+    <Compile Include="CollectionView\CarouselViewDelegator.cs" />
     <Compile Include="CollectionView\CarouselViewRenderer.cs" />
     <Compile Include="CollectionView\CollectionViewRenderer.cs" />
     <Compile Include="CollectionView\EmptySource.cs" />
     <Compile Include="CollectionView\GroupableItemsViewController.cs" />
+    <Compile Include="CollectionView\GroupableItemsViewDelegator.cs" />
     <Compile Include="CollectionView\GroupableItemsViewRenderer.cs" />
     <Compile Include="CollectionView\HorizontalCell.cs" />
     <Compile Include="CollectionView\HorizontalDefaultSupplementalView.cs" />
     <Compile Include="CollectionView\ObservableGroupedSource.cs" />
     <Compile Include="CollectionView\ScrollToPositionExtensions.cs" />
     <Compile Include="CollectionView\SelectableItemsViewController.cs" />
+    <Compile Include="CollectionView\SelectableItemsViewDelegator.cs" />
     <Compile Include="CollectionView\SelectableItemsViewRenderer.cs" />
     <Compile Include="CollectionView\TemplateHelpers.cs" />
-    <Compile Include="CollectionView\UICollectionViewDelegator.cs" />
+    <Compile Include="CollectionView\ItemsViewDelegator.cs" />
     <Compile Include="CollectionView\VerticalCell.cs" />
     <Compile Include="CollectionView\StructuredItemsViewController.cs" />
     <Compile Include="CollectionView\StructuredItemsViewRenderer.cs" />