Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Bug] [Android] CollectionView has incorrect VerticalOffset after using ScrollTo method #10966

Open
InquisitorJax opened this issue Jun 5, 2020 · 7 comments

Comments

@InquisitorJax
Copy link

Description

After calling ItemsCollectionView.ScrollTo(0, animate: false) on Android, the collectionview will report the incorrect VerticalOffset on the scrolled event

Steps to Reproduce

  1. Create new Xamarin project from Shell Template
  2. Add Items to MockDataStore to make the landing page scrollable
  3. Add a button to the UI which scrolls the CollectionView: ItemsCollectionView.ScrollTo(0, animate: false)
  4. Add a Scrolled event handler for the collection view to debug the VerticalOffset property
  5. Run the app: Scroll to the bottom of the list, and then press the button (which programmatically scrolls the collectionview to the top) - now continue to scroll -> the collection view is not reporting incorrect VerticalOffset values (ie. when back to the first position, verticalOffset is no longer 0)

This works as expected on iOS.

Expected Behavior

  • VerticalOffSet should report 0 value when collectionview is at first item after calling ScrollTo method.

Actual Behavior

  • The collectionview is not resetting the verticalOffset value after calling ScrollTo

Basic Information

  • Version with issue: latest
  • Last known good version: ??
  • IDE: latest
  • Platform Target Frameworks: Tested on API 29 device

Screenshots

image

@InquisitorJax InquisitorJax added s/unverified New report that has yet to be verified t/bug 🐛 labels Jun 5, 2020
@pauldipietro pauldipietro added this to New in Triage Jun 5, 2020
@jsuarezruiz
Copy link
Contributor

@InquisitorJax What version of Xamarin.Forms are you using?, could you attach the reproduction sample?

@jsuarezruiz jsuarezruiz moved this from New to Needs Info in Triage Jun 5, 2020
@jsuarezruiz jsuarezruiz added the s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. label Jun 5, 2020
@InquisitorJax
Copy link
Author

@InquisitorJax What version of Xamarin.Forms are you using?, could you attach the reproduction sample?

latest

@InquisitorJax
Copy link
Author

CVBugs.zip

@samhouts samhouts removed the s/needs-info ❓ A question has been asked that requires an answer before work can continue on this issue. label Jun 8, 2020
@samhouts samhouts moved this from Needs Info to New in Triage Jun 8, 2020
@hartez hartez added e/3 🕒 3 and removed s/unverified New report that has yet to be verified labels Jun 10, 2020
@hartez hartez added this to Backlog in CollectionView via automation Jun 10, 2020
@hartez hartez removed this from New in Triage Jun 10, 2020
@samhouts samhouts added this to the 5.0.0 milestone Aug 13, 2020
@samhouts samhouts added this to To do in vNext+1 (5.0.0) Aug 13, 2020
@samhouts samhouts removed this from the 5.0.0 milestone Nov 2, 2020
@SangI762
Copy link

Same here. Any workarounds?

@sokrog
Copy link

sokrog commented Dec 16, 2022

Have the same problem

@valentasm1
Copy link

Same here. Any workarounds?

@valentasm1
Copy link

This solution solved issue for me. At least for now. Need more testing.
Create custom collection view rendered and create custom RecyclerViewScrollListener

[assembly: ExportRenderer(typeof(CollectionView), typeof(AppCollectionViewRenderer))]
namespace Mobile.Droid.Renderers
{
    public class AppCollectionViewRenderer : CollectionViewRenderer
    {
        public AppCollectionViewRenderer(Context context) : base(context)
        {
        }

        protected override RecyclerViewScrollListener<GroupableItemsView, IGroupableItemsViewSource> CreateScrollListener()
        {
            return new CustomAppRecyclerViewScrollListener<GroupableItemsView, IGroupableItemsViewSource>(ItemsView, ItemsViewAdapter);
        }
    }
}

All code is identical to xamarin side except i removed call to base and always calculate _verticalOffset from recyclerView

public class CustomAppRecyclerViewScrollListener<TItemsView, TItemsViewSource> : RecyclerViewScrollListener<TItemsView, TItemsViewSource>
    where TItemsView : ItemsView
    where TItemsViewSource : IItemsViewSource
{
    private int _horizontalOffset, _verticalOffset;
    private readonly TItemsView _itemsView;

    public CustomAppRecyclerViewScrollListener(TItemsView itemsView, ItemsViewAdapter<TItemsView, TItemsViewSource> itemsViewAdapter, bool getCenteredItemOnXAndY = false) : base(itemsView, itemsViewAdapter, getCenteredItemOnXAndY)
    {
        _itemsView = itemsView;
        ItemsViewAdapter = itemsViewAdapter;
    }

    public override void OnScrolled(RecyclerView recyclerView, int dx, int dy)
    {
        //Sending to based trigger event twice with wrong _verticalOffset value
        //Not sending could be a problem for some cases
        //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;        

        int offset = recyclerView.ComputeVerticalScrollOffset();
        _verticalOffset = offset;


        var (first, center, last) = GetVisibleItemsIndex(recyclerView);

        var context = recyclerView.Context;
        var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
        {
            HorizontalDelta = context.FromPixels(dx),
            VerticalDelta = context.FromPixels(dy),
            HorizontalOffset = context.FromPixels(_horizontalOffset),
            //Old code aka original from xamarin github
            //VerticalOffset = context.FromPixels(_verticalOffset),
            VerticalOffset = _verticalOffset,
            FirstVisibleItemIndex = first,
            CenterItemIndex = center,
            LastVisibleItemIndex = last
        };


        _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 (last == -1)
        {
            return;
        }

        switch (_itemsView.RemainingItemsThreshold)
        {
            case -1:
                return;
            case 0:
                if (last == ItemsViewAdapter.ItemCount - 1)
                {
                    _itemsView.SendRemainingItemsThresholdReached();
                }

                break;
            default:
                if (ItemsViewAdapter.ItemCount - 1 - last <= _itemsView.RemainingItemsThreshold)
                {
                    _itemsView.SendRemainingItemsThresholdReached();
                }

                break;
        }
    }
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
CollectionView
  
Review Backlog
Development

No branches or pull requests

7 participants