You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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; 
}

关键改动说明

  1. 预判目标scrollX:在调用scrollBy之前,先计算targetScrollX = getScrollX() + dx,判断这个值是否在你允许的范围内(≥0且<mSlideViewWidth)。
  2. 修正dx值:如果目标值超出边界,就把dx调整到刚好让scrollX停在边界的位置,比如当targetScrollX<0时,dx设置为-getScrollX(),这样scrollBy(dx,0)之后scrollX就会变成0,不会出现负数的情况。
  3. 优化ACTION_DOWN的逻辑:把scroller终止的逻辑移到DOWN事件里,避免MOVE事件里重复判断,逻辑更合理。

这样修改后,你的ViewGroup就不会再出现向左滑出边界的情况了,所有滚动都会被限制在你设定的范围内。

内容的提问来源于stack exchange,提问作者wzt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 08:32:53