【发布时间】:2021-01-15 11:48:26
【问题描述】:
我想在投掷后停止 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();
}
}
扩展的 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;
}
}
【问题讨论】:
-
我试图重现您的问题,但我缺少有关
IScrollable、DispatchOnUpOrCancelMotionEvent、DispatchOnDownMotionEvent和GetCurrentScrollY的部分代码您能分享这些代码吗?提供可以重现此问题的演示更好, -
@LeonLu-MSFT 我在 GitHub 上创建了演示项目 TestNestedScrollView
标签: android xamarin android-nestedscrollview