自定义ViewGroup滚动边界控制异常求助:已限制getScrollX()≥0时可滚动,向左滑动仍出现偏移
问题分析与解决方案
嘿,我刚仔细看了你的代码,发现问题出在你判断的是当前的scrollX,而没有预判scrollBy之后的结果是否会超出边界。举个例子:当你的ViewGroup初始scrollX是0时,第一次触发ACTION_MOVE,此时满足getScrollX()>=0的条件,你调用了scrollBy(dx,0)——但如果dx是负数(比如用户向左滑动导致的计算结果),scrollX就会变成0+dx,直接小于0,这就出现了你看到的“向左滑一小段”的情况,等下一次MOVE事件触发时,scrollX已经是负数,才会被拦截,但已经晚了一步。
而且还有个小细节:scrollBy(dx,0)的逻辑是内容相对于View的偏移,正数dx会让内容左移(scrollX增大),负数dx会让内容右移(scrollX减小),你的dx计算int dx=mLastX-x可能需要再确认方向是否符合你的需求,但核心的边界判断逻辑是关键问题。
修改后的代码
@Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int x=(int)event.getX(); if (action == MotionEvent.ACTION_DOWN) { mLastX = x; mStart = getScrollX(); // 按下时如果scroller还在动画,直接终止 if (!mScroller.isFinished()) { mScroller.abortAnimation(); } } else if (action == MotionEvent.ACTION_MOVE) { int dx = mLastX - x; // 计算scrollBy之后的目标scrollX int targetScrollX = getScrollX() + dx; // 修正dx,确保targetScrollX不会超出允许范围(≥0,<mSlideViewWidth) if (targetScrollX < 0) { // 如果目标scrollX小于0,只滚动到0的位置 dx = -getScrollX(); } else if (targetScrollX >= mSlideViewWidth) { // 如果目标scrollX超过上限,只滚动到上限位置 dx = mSlideViewWidth - getScrollX(); } // 执行滚动(只有dx不为0时才触发,避免无效操作) if (dx != 0) { scrollBy(dx, 0); } mLastX = x; } else if (action == MotionEvent.ACTION_UP) { mEnd = getScrollX(); // 保留兜底逻辑,防止快速滑动等极端情况导致的边界溢出 if(getScrollX() < 0){ mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0); } else if (getScrollX() >= mSlideViewWidth) { mScroller.startScroll(getScrollX(), 0, mSlideViewWidth - getScrollX(), 0); } } postInvalidate(); return true; }
关键改动说明
- 预判目标scrollX:在调用
scrollBy之前,先计算targetScrollX = getScrollX() + dx,判断这个值是否在你允许的范围内(≥0且<mSlideViewWidth)。 - 修正dx值:如果目标值超出边界,就把dx调整到刚好让scrollX停在边界的位置,比如当targetScrollX<0时,dx设置为
-getScrollX(),这样scrollBy(dx,0)之后scrollX就会变成0,不会出现负数的情况。 - 优化ACTION_DOWN的逻辑:把scroller终止的逻辑移到DOWN事件里,避免MOVE事件里重复判断,逻辑更合理。
这样修改后,你的ViewGroup就不会再出现向左滑出边界的情况了,所有滚动都会被限制在你设定的范围内。
内容的提问来源于stack exchange,提问作者wzt
相关产品推荐
相关产品推荐

