When enabling grouping and setting RemainingItemsThreshold on a CollectionView on iOS RemainingItemsThresholdReachedCommand is only executed once. After that RemainingItemsThresholdReached and RemainingItemsThresholdReachedCommand are not called when the threshold is reached. On Android the CollectionView behaves as expected.
When scrolling down, new items should automatically load when reaching the end of the list, like on Android.
When scrolling down, only one group is loaded, when scrolling again to the end of the list no subsequent groups are loaded. This occurs on the iOS simulator and on an iPhone 8 with iOS 13.2.
https://github.com/kramer-e/CollectionViewInfiniteScrollingBug
Same for me.
Any update?
Recently I ran into the same problem as described here. Upon debugging / looking at the source I figured out the event is triggered by the "scrolled" method inside "ItemsViewDelegator" class. This method does not take the grouping in account when calculating the "*itemIndex". Therefor the switch statement responsible for triggering the "itemsThreshold" event will never produce anything usable. My work-around is as follows:
Custom renderer
public class CustomCollectionViewRenderer : CollectionViewRenderer
{
protected override GroupableItemsViewController<GroupableItemsView> CreateController(GroupableItemsView itemsView, ItemsViewLayout layout)
{
return new CustomGroupableItemsViewController<GroupableItemsView>(itemsView, layout);
}
}
Custom controller
public class CustomGroupableItemsViewController<TItemsView> : GroupableItemsViewController<TItemsView>
where TItemsView : GroupableItemsView
{
public CustomGroupableItemsViewController(TItemsView groupableItemsView, ItemsViewLayout layout)
: base(groupableItemsView, layout)
{
}
protected override UICollectionViewDelegateFlowLayout CreateDelegator()
{
return new CustomGroupableItemsViewDelegator<TItemsView, CustomGroupableItemsViewController<TItemsView>>(ItemsViewLayout, this);
}
}
Custom delegator
public class CustomGroupableItemsViewDelegator<TItemsView, TViewController> : GroupableItemsViewDelegator<TItemsView, TViewController>
where TItemsView : GroupableItemsView
where TViewController : GroupableItemsViewController<TItemsView>
{
public CustomGroupableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
: base(itemsViewLayout, itemsViewController)
{
}
public override void Scrolled(UIScrollView scrollView)
{
List<NSIndexPath> indexPathsForVisibleItems =
ViewController.CollectionView.IndexPathsForVisibleItems.OrderBy(x => x.Row).ToList();
if (indexPathsForVisibleItems.Count == 0)
return;
TItemsView itemsView = ViewController.ItemsView;
IItemsViewSource source = ViewController.ItemsSource;
UIEdgeInsets contentInset = scrollView.ContentInset;
nfloat contentOffsetX = scrollView.ContentOffset.X + contentInset.Left;
nfloat contentOffsetY = scrollView.ContentOffset.Y + contentInset.Top;
UICollectionView collectionView = ViewController.CollectionView;
CGPoint centerPoint = new CGPoint(collectionView.Center.X + collectionView.ContentOffset.X,
collectionView.Center.Y + collectionView.ContentOffset.Y);
NSIndexPath centerIndexPath = collectionView.IndexPathForItemAtPoint(centerPoint);
NSIndexPath firstVisibleItem = indexPathsForVisibleItems.First();
NSIndexPath centerItem = centerIndexPath ?? firstVisibleItem;
NSIndexPath lastVisibleItem = indexPathsForVisibleItems.Last();
// Changed code
int firstVisibleItemIndex = GetItemIndexWithGrouping(firstVisibleItem, source);
int centerItemIndex = GetItemIndexWithGrouping(centerItem, source);
int lastVisibleItemIndex = GetItemIndexWithGrouping(lastVisibleItem, source);
ItemsViewScrolledEventArgs itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
{
HorizontalDelta = contentOffsetX - PreviousHorizontalOffset,
VerticalDelta = contentOffsetY - PreviousVerticalOffset,
HorizontalOffset = contentOffsetX,
VerticalOffset = contentOffsetY,
FirstVisibleItemIndex = firstVisibleItemIndex,
CenterItemIndex = centerItemIndex,
LastVisibleItemIndex = lastVisibleItemIndex
};
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;
}
}
// Added code
private static int GetItemIndexWithGrouping(NSIndexPath indexPath, IItemsViewSource itemSource)
{
int index = (int)indexPath.Item;
if (indexPath.Section > 0)
{
for (int i = 0; i < indexPath.Section; i++)
{
index += itemSource.ItemCountInGroup(i);
}
}
return index;
}
}
If it's useful/wanted I can make a PR for this repository, but I'm not sure it's the best fix possible. :)
Thank you for investigating and sharing the workaround, I just tested it and works. @rmarinho I hope someone from the Forms team can verify this fix.
This kind of code should be in a common class shared by the different platforms.
@RSchipper if you haven't done so already, feel free to open a PR. That will make it easier for us to test this and verify the actual fix since we can just look at the code as it is integrated in our solution instead of having to copy/paste and figure it out ourselves. Thanks :)
@jfversluis Do you have any idea when this is going to be fixed ? Thanks
Hi any news on this one? many thanks
@samhouts Any progress ?
Most helpful comment
Thank you for investigating and sharing the workaround, I just tested it and works. @rmarinho I hope someone from the Forms team can verify this fix.