protected virtual (int First, int Center, int Last) GetVisibleItemsIndex(RecyclerView recyclerView) { var firstVisibleItemIndex = -1; var lastVisibleItemIndex = -1; var centerItemIndex = -1; if (recyclerView.GetLayoutManager() is LinearLayoutManager linearLayoutManager) { firstVisibleItemIndex = linearLayoutManager.FindFirstVisibleItemPosition(); lastVisibleItemIndex = linearLayoutManager.FindLastVisibleItemPosition(); centerItemIndex = recyclerView.CalculateCenterItemIndex(firstVisibleItemIndex, linearLayoutManager, _getCenteredItemOnXAndY); } return(firstVisibleItemIndex, centerItemIndex, lastVisibleItemIndex); }
public override void OnScrolled(RecyclerView recyclerView, int dx, int dy) { base.OnScrolled(recyclerView, dx, dy); // TODO: These offsets will be incorrect upon row size or count change. // They are currently provided in place of LayoutManager's default offset calculation // because it does not report accurate values in the presence of uneven rows. // See https://stackoverflow.com/questions/27507715/android-how-to-get-the-current-x-offset-of-recyclerview _horizontalOffset += dx; _verticalOffset += dy; var firstVisibleItemIndex = -1; var lastVisibleItemIndex = -1; var centerItemIndex = -1; if (recyclerView.GetLayoutManager() is LinearLayoutManager linearLayoutManager) { firstVisibleItemIndex = linearLayoutManager.FindFirstVisibleItemPosition(); lastVisibleItemIndex = linearLayoutManager.FindLastVisibleItemPosition(); centerItemIndex = recyclerView.CalculateCenterItemIndex(firstVisibleItemIndex, linearLayoutManager); } var context = recyclerView.Context; var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs { HorizontalDelta = context.FromPixels(dx), VerticalDelta = context.FromPixels(dy), HorizontalOffset = context.FromPixels(_horizontalOffset), VerticalOffset = context.FromPixels(_verticalOffset), FirstVisibleItemIndex = firstVisibleItemIndex, CenterItemIndex = centerItemIndex, LastVisibleItemIndex = lastVisibleItemIndex }; _itemsView.SendScrolled(itemsViewScrolledEventArgs); // Don't send RemainingItemsThresholdReached event for non-linear layout managers // This can also happen if a layout pass has not happened yet if (lastVisibleItemIndex == -1) { return; } switch (_itemsView.RemainingItemsThreshold) { case -1: return; case 0: if (lastVisibleItemIndex == _itemsViewAdapter.ItemCount - 1) { _itemsView.SendRemainingItemsThresholdReached(); } break; default: if (_itemsViewAdapter.ItemCount - 1 - lastVisibleItemIndex <= _itemsView.RemainingItemsThreshold) { _itemsView.SendRemainingItemsThresholdReached(); } break; } }