jamesmontemagno / Xamarin.Forms-PullToRefreshLayout

Pull To Refresh a ScrollView or ListView in Xamarin.Forms
218 stars 49 forks source link

Child ScrollView still has a negative ScrollY after IsRefresh is set to false (iOS only) #39

Closed elneilios closed 4 years ago

elneilios commented 6 years ago

Since updating our Nuget package to the latest version (2.2.1) we are now finding that the ScrollView is being given a negative ScrollY value after programatically setting IsRefresh to false once the async operation has completed.

It seems the ScrollY is moving back to the value that is required to initiate the refresh. e.g.

  1. Initial state is ScrollY of 0
  2. Pull gesture requires a ScrollY of -124 to initiate the refresh
  3. ScrollY settles at -60.5 whilst refreshing
  4. ScrollY is set back to -124 when IsRefresh is set to false

This seems to only affect iOS

elneilios commented 6 years ago

If anyone else is experiencing this, here is my dodgy workaround!

pullToRefreshLayout.PropertyChanged += (s, e) =>
{
    if (e.PropertyName == nameof(pullToRefreshLayout.IsRefreshing))
    {
        // IsRefreshing has been set to false
        // After a short delay, if we still have a negative ScrollY set the ScrollView.ScrollY back to 0
        if (!pullToRefreshLayout.IsRefreshing)
        {
            Task.Delay(100).ContinueWith(t =>
            {
                if (scrollView.ScrollY < 0)
                    scrollView.ScrollToAsync(0, 0, true);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
    }
};
lprichar commented 6 years ago

Downgrading to 2.2.0 fixes it as well. Can't find release notes, so not sure what I lose by doing that, but that version seems to work great on latest versions of iOS and Android.

taublast commented 5 years ago

@elneilios Nice, thanks man! Have put this in forked renderer, fixed it:

     if (view is UIScrollView)
            {
                var uiScrollView = view as UIScrollView;

                if (!set)
                {
                    origininalY = uiScrollView.ContentOffset.Y;
                    set = true;
                }

                if (origininalY < 0)
                    return true;

                if (refreshing)
                    uiScrollView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY - refreshControl.Frame.Size.Height), true);
                else
                {
                    //for some buggy reason we need a delay here
                    Task.Delay(100).ContinueWith(t =>
                        {
                            uiScrollView.SetContentOffset(new CoreGraphics.CGPoint(0,0), true);
                        }, TaskScheduler.FromCurrentSynchronizationContext());
                }
                return true;
            }
jamesmontemagno commented 4 years ago

Please use the RefreshView as this is officially deprecated now https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/refreshview