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;
            }
        }