当 SmoothScrollTo(0, 0) 调用时如何停止 NestedScrollView 滚动

问题描述

我想在滑动后停止 nestedScrollview 滚动动画并以编程方式平滑滚动到顶部。 在我的例子中,SmoothScrollTo(0,0) 工作正常,但在它之后之前的滚动动画继续了一点。

我发现了非常相似的问题: How to stop scroll in progress in NestedScrollView?

但是 Keivan Esbati 的回答对我不起作用。有人可以帮我吗?

以编程方式调用滚动到顶部:

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

扩展的嵌套滚动视图:

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

解决方法

首先,我看到您的项目仍在使用 Android 支持包,请升级它们以使用 AndroidX 以获得更好的体验。您可以参考 AndroidX migration in Xamarin.Forms 了解更多信息,其中还包括如何迁移软件包。

我检查了另一个线程并尝试了一个干净的演示,但它对我也不起作用,但我确实找到了另一个对我有用的建议:https://stackoverflow.com/a/59333212/12936075

您可以制作 FabOnClick:

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