0

I want to stop NestedScrollview scrolling animation after fling and programmatically scroll to top smoothly. In my case SmoothScrollTo(0, 0) works correct but after it previous scrolling animation continued a little.

I found very similar question: How to stop scroll in progress in NestedScrollView?

But answer of Keivan Esbati doesn't work for me. Can anybody help me?

Programmatically called scroll to top:

    public void ScrollToTop()
        {
            if (!IsOnTopOfScroll())
            {
                ObjectAnimator.OfInt(scrollView, "scrollY", scrollView.Top).SetDuration(150).Start();
            }
        }

Extended NestedScrollView:

public class ObservableNestedScrollView : NestedScrollView, IScrollable
{
        private const int MAX_SCROLL_FACTOR = 1;
        private bool isAutoScrolling;

        public override void ScrollTo(int x, int y)
        {
            isAutoScrolling = true;
            base.ScrollTo(x, y);
        }

      public override bool OnInterceptTouchEvent(MotionEvent ev)
        {
            if (isAutoScrolling)
            {
                return base.OnTouchEvent(ev);
            }

            if (hasNoCallbacks())
            {
                return base.OnInterceptTouchEvent(ev);
            }
            switch (ev.ActionMasked)
            {
                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    mDragging = false;
                    DispatchOnUpOrCancelMotionEvent(mScrollState);
                    return false;
                case MotionEventActions.Down:
                    mFirstScroll = mDragging = true;
                    DispatchOnDownMotionEvent();
                    break;
            }
            return base.OnInterceptTouchEvent(ev);
        }

        public override bool OnTouchEvent(MotionEvent ev)
        {
            if (isAutoScrolling)
            {
                return base.OnTouchEvent(ev);
            }

            if (hasNoCallbacks())
            {
                return base.OnTouchEvent(ev);
            }

            switch (ev.ActionMasked)
            {
                case MotionEventActions.Up:
                case MotionEventActions.Cancel:
                    mIntercepted = false;
                    mDragging = false;
                    DispatchOnUpOrCancelMotionEvent(mScrollState);
                    break;
                case MotionEventActions.Move:
                    if (mPrevMoveEvent == null)
                    {
                        mPrevMoveEvent = ev;
                    }
                    float diffY = ev.GetY() - mPrevMoveEvent.GetY();
                    mPrevMoveEvent = MotionEvent.ObtainNoHistory(ev);
                    if (GetCurrentScrollY() - diffY <= 0)
                    {

                        if (mIntercepted)
                        {
                            return false;
                        }

                        ViewGroup parent;
                        if (mTouchInterceptionViewGroup == null)
                        {
                            parent = (ViewGroup)Parent;
                        }
                        else
                        {
                            parent = mTouchInterceptionViewGroup;
                        }

                        float offsetX = 0;
                        float offsetY = 0;
                        for (View v = this; v != null && v != parent; v = (View)v.Parent)
                        {
                            offsetX += v.Left - v.ScrollX;
                            offsetY += v.Top - v.ScrollY;
                        }

                        MotionEvent mEvent = MotionEvent.ObtainNoHistory(ev);
                        mEvent.OffsetLocation(offsetX, offsetY);

                        if (parent.OnInterceptTouchEvent(mEvent))
                        {
                            mIntercepted = true;

                            mEvent.Action = MotionEventActions.Down;

                            Post(new RunnableAnonymousInnerClassHelper(parent, mEvent));
                            return false;
                        }
                        return base.OnTouchEvent(ev);
                    }
                    break;
            }

            return base.OnTouchEvent(ev);
        }

        protected override void OnScrollChanged(int x, int y, int oldX, int oldY)
        {
            base.OnScrollChanged(x, y, oldX, oldY);

            if (isAutoScrolling)
            {
                if (System.Math.Abs(y - oldY) < MAX_SCROLL_FACTOR || y >= MeasuredHeight || y == 0
                        || System.Math.Abs(x - oldX) < MAX_SCROLL_FACTOR || x >= MeasuredWidth || x == 0)
                {
                    isAutoScrolling = false;
                }
            }

            if (hasNoCallbacks())
            {
                return;
            }
            mScrollY = y;

            DispatchOnScrollChanged(y, mFirstScroll, mDragging);
            if (mFirstScroll)
            {
                mFirstScroll = false;
            }

            if (mPrevScrollY < y)
            {
                mScrollState = ScrollState.UP;
            }
            else if (y < mPrevScrollY)
            {
                mScrollState = ScrollState.DOWN;
                //} else {
            }
            mPrevScrollY = y;
        }
}
AlexTsy
  • 11
  • 2
  • 3
  • I tried to reproduce your issue, but I lack part of the code about `IScrollable`, `DispatchOnUpOrCancelMotionEvent` `DispatchOnDownMotionEvent` and `GetCurrentScrollY` Could you share these codes? Provide a demo that could reproduce this issue is better, – Leon Lu - MSFT Jan 15 '21 at 12:45
  • @LeonLu-MSFT I created demo project on GitHub [TestNestedScrollView](https://github.com/AlexTsybin/TestNestedScrollView) – AlexTsy Jan 15 '21 at 17:10

1 Answers1

0

First of all, I saw your project is still utilizing Android Support packages, please upgrade them to use AndroidX for better experience. You can refer to AndroidX migration in Xamarin.Forms for more information, it also includes how to migrate the packages.

I checked the other thread and tried in a clean demo, but it's not working for me either, but I do find another suggestions which works for me: https://stackoverflow.com/a/59333212/12936075

You can make your FabOnClick:

    private void FabOnClick(object sender, EventArgs eventArgs)
    {
        scrollView.Fling(0);
        scrollView.SmoothScrollTo(0, 0);
    }